How would you split this String format into parts:
message_type={any_text}&message_number={digits}&code={digits}&id={digits}&message={any_text}×tamp={digits_with_decimal}
Where in the message={any_text} part, the {any_text} may contain a & and a = thus not being able to do String split by & or =
And the order of the message parts may be scrambled or not in this order. I am thinking that a pattern can be extracted for a solution, ={the_text_needed}& however this would not apply for the last part of the String as there will be no & at the end.
I hope this will work -
String originalString = "message_type={a&=b}&message_number={1}&code={2}&id={3}&message={a&=b}×tamp={12}";
Map<String, String> resultMap = new HashMap<String, String>();
String[] splitted1 = originalString.split("&+(?![^{]*})");
for (String str : splitted1) {
String[] splitted2 = str.split("=+(?![^{]*})");
resultMap.put(splitted2[0], splitted2[1]);
splitted2 = null;
}
If parameter values are not enclosed within curly braces, then its really tough. I can think of a solution, but I don't know whether it could break in some situation or not -
String originalString = "message_type=msgTyp&message_number=1&code=2&message=a&=b×tamp=12";
String[] predefinedParameters = {"message_type", "message_number", "code", "message", "timestamp"};
String delimeter = "###";
for (String str : predefinedParameters) {
originalString = originalString.replace(str+"=", delimeter+str+"=");
}
originalString = originalString.substring(delimeter.length());
String[] result = originalString.split("&"+delimeter);
Assuming that none of the fields contain & or =, you could:
String[] fields = message.split("&");
Map<String,String> fieldMap = new LinkedHashMap<>();
for (String field:fields)
{
String[] fieldParts = field.split("=");
fieldMap.put(fieldParts[0],fieldParts[1]);
}
and have a map of all your fields.
That you are trying to do is to parse a querystring , you should check:
Query String Manipulation in Java
Related
I want to extract specific substrings from a string:
String source = "info1 info1ContentA info1ContentB info3 info3ContentA info3ContentB"+
"info2 info2ContentA";
The result should be:
String info1 ="info1ContentA info1ContentB";
String info2 ="info2ContentA";
String info3 ="info3ContentA info3ContentB";
For me it's very difficult to extract the informations, because sometimes after "info" their are one, two or more content informations. Another problem that occurs is, that the order of info1, info2 etc. is not sorted and the "real data" doesn't contain a ascending number.
My first idea was to add info1, info2, info3 etc to an ArrayList.
private ArrayList<String> arr = new ArrayList<String>();
arr.add("info1");
arr.add("info2");
arr.add("info3");
Now I want to extract the substring with the method StringUtils.substringBetween() from Apache Commons (https://mvnrepository.com/artifact/org.apache.commons/commons-lang3/3.4):
String result = StringUtils.substringBetween(source, arr.get(0), arr.get(1));
This works, if info1 is in the string before info2, but like I said the "real data" is not sorted.
Any idea how I can fix this?
Split those string by space and then use String's method startsWith to add the part to proper result string
Map<String, String> resultMap = new HashMap<String, String>();
String[] prefixes = new String[]{"info1", "info2", "info3"};
String source = "info1 info1ContentA info1ContentB info3 info3ContentA info3ContentB"+" info2 info2ContentA";
String[] parts = source.split(" ");
for(String part : parts) {
for(String prefix : prefixes) {
if(part.startsWith(prefix) {
String currentResult = (resultMap.containsKey(prefix) ? resultMap.get(prefix) + part + " " : part);
resultMap.put(prefix, currentResult);
}
}
}
Also consider using StringBuilder instead of adding string parts
If you cannot be sure that parts will be embraces with spaces you can change at the beginning all part to <SPACE>part in your source string using String replace method
You can use a regular expression, like this:
String source = "info1 info1ContentA info1ContentB info3 info3ContentA info3ContentB info2 info2ContentA";
for (int i = 1; i < 3; i++) {
Pattern pattern = Pattern.compile("info" + i + "Content[A-Z]");
Matcher matcher = pattern.matcher(source);
List<String> matches = new ArrayList<>();
while (matcher.find()) {
matches.add(matcher.group());
}
// process the matches list
}
I have a piece of data in the following formats/patterns :
String inputFruit = "[Apple,Banana(Mango-Juice,lemon-Pickle,Grape-Drinks)]";
String inputFruit = "Apple,Banana(Mango-Juice,lemon-Pickle,Grape-Drinks)"
String inputFruit = "Apple(Mango-Juice,lemon-Pickle,Grape-Drinks)Banana"
Now I have to extract and store individual datas like :
firstFruit = Apple
secondFruit = Banana
miscFruit = Mango-Juice,lemon-Pickle,Grape-Drinks
I have the following code snippet which I am using :
public static void splitFruits(String inputFruit)
{
String firstFruit = StringUtils.EMPTY;
String secondFruit = StringUtils.EMPTY;
String miscFruit = StringUtils.EMPTY;
inputFruit = inputFruit.replaceAll("\\[" , "");
inputFruit = inputFruit.replaceAll("\\]" , "");
String frts[] = inputFruit.split("\\("");
String frtp[] = frts[0].split(",");
firstFruit = frtp[0];
secondFruit = frtp[1];
miscFruit = frts[1];
}
Here I need to store Apple in variable firstFruit, Banana in secondFruit, and whatever is there inside () in miscFruit.
My code is able to extract value for a specific patter mentioned in no 1.How can I create pattern match statements to match with input values in all the above specified 3 different formats and store them separately.
Instead of using frts[0] to get the first and second fruits, combine frts[0] and frts[2] (that is, the parts on either side of the parenthetical section) and split that.
I want to parse the data below in java. What approach shall I follow?
I want to neglect ; inside { }.
Thus Version, Content, Provide, UserConfig and Icon as name and corresponding values.
Version:"1";
Content:2013091801;
Provide:"Airtel";
UserConfig :
{
Checksum = "sha1-234448e7e573b6dedd65f50a2da72245fd3b";
Source = "content\\user.ini";
};
Icon:
{
Checksum = "sha1-a99f835tytytyt3177674489770e613c89390a8c4";
Source = "content\\resept_ico.bmp";
};
Here we can't use String.split(";") function.
It would have been lot more complex to convert using the Regex and then creating a method to extract the required fields,
What I did was converted the above mentioned input to Json compatible string and then used GSON library by google to parse the String to my customized class,
class MyVer
{
String Version;
long Content;
String Provide;
Config UserConfig;
Config Icon;
String Source;
}
class Config
{
String Checksum;
String Source;
}
public static void main(String[] args)
{
String s = "Version:\"1\";Content:2013091801;Provide:\"Airtel\";UserConfig :{ Checksum = \"sha1-234448e7e573b6dedd65f50a2da72245fd3b\"; Source = \"content\\user.ini\";};Icon:{ Checksum = \"sha1-a99f835tytytyt3177674489770e613c89390a8c4\"; Source = \"content\\resept_ico.bmp\";};";
String startingBracePattern = Pattern.quote("{");
String endBracePattern = Pattern.quote("}");
s=s.replaceAll(Pattern.quote("\\"), "\\\\\\\\"); //Replacing all the single \ with double \\
s = s.replaceAll("\\s*"+startingBracePattern +"\\s*", "\\{\""); //Replacing all the `spaces { spaces` with `{"` MEANS all the { to replace with {"
s = s.replaceAll(";\\s*"+endBracePattern +"\\s*;", "\\};"); //Replacing all the `; spaces } spaces ;` with `},"` MEANS all the ;}; to replace with };
s = "{\"" + s.substring(0, s.length() - 1) +"}"; //Removing last ; and appending {" and }
s = s.replaceAll("\\s*:", "\":"); // Replacing all the `space with :` with `":`
s = s.replaceAll("\\s*;\\s*", ",\""); //Replacing all the `spaces ; spaces` with `,"`
s = s.replaceAll("\\s*=\\s*", "\":"); //Replacing all the `spaces = spaces` with `":`
Gson gson = new Gson();
MyVer newObj = gson.fromJson(s, MyVer.class);
}
This converts and give you the object of MyVer and then you can access all the variables.
NOTE: You can alter the code little to replace all \r\n if they are present in your input variables. I have not used them and your actual data supplied in question in a single line for simplicity.
JSON sounds a lot easier in this case..
.. however, if you were to do this using regular expressions, one way would be:
for the simple cases (eg. version):
// look for Version: some stuff ;
Pattern versionPattern = Pattern.compile("Version\\s*:\\s*\"\\w+\"\\s*;");
// the whole big string you're looking in
String bigString = ...; // the entire string from before can go here
// create a matcher for the "version pattern"
Matcher versionMatcher = versionPattern.matcher(bigString);
// check if there's a match in the string
if(versionMatcher.find()) {
// get the matching substring
String matchingSubstring = bigString.substring(
versionMatcher.start(),
versionMatcher.end()
);
// we need the area between the quotes
String version = matchingSubstring.split("\"")[1];
// do something with it
...
}
for the harder (multi-line) cases (eg. UserConfig):
// look for UserConfig : { some stuff };
Pattern userconfigPattern = Pattern.compile("UserConfig\\s*:\\s*{[^}]*};", Pattern.DOTALL);
// create a matcher for the "user config pattern"
Matcher userconfigMatcher = userconfigPattern.matcher(bigString);
// check if there's a match in the string
if(userconfigMatcher.find()) {
// get the matching substring
String matchingSubstring = bigString.substring(
userconfigMatcher.start(),
userconfigMatcher.end()
);
// we need the area between the curly braces
String version = matchingSubstring.split("[{}]")[1];
// do something with it
...
}
EDIT: this is probably an easier way
// split the input string into fields
String[] fields = bigString.split("[^:]+:([^{;]+;)|({[^}]+};)");
// for each key-value pair
for(String field : fields) {
// the key and value are separated by colons
String parts = field.split(":");
String key = parts[0];
String value = parts[1];
// do something with them, or add them to a map
...
}
This last way splits the input string based on the assumption that each key-value pair consists of:
some (non-colon) characters at the start, followed by
a colon,
either
-> some characters that are not curly braces or semi-colons (for simple attributes), or
-> curly braces containing some characters that are not curly braces
a semi-colon
Here is json solution
str = "{" + str.substring(0, str.lastIndexOf(";")).replace(";\n}", "}") + "}";
try {
JSONObject json = new JSONObject(str);
String version = json.getString("Version");
JSONObject config = json.getJSONObject("UserConfig");
String source = config.getString("Source");
} catch (JSONException e) {
e.printStackTrace();
}
since ";" should not be in front of "}"
Source = "content\\resept_ico.bmp";
}
we need remove them
I've a tricky condition which does not seem to work. For a given string, "Hi [HandleKey], you have [Action]", and a map which contains, map<"HandleKey","Peter"> I want to replace the square bracket and the word within if the key is found in the map. In this case, the map does not contain the key Action. The string should return "Hi Peter, you have [Action]".
Here is the code that I'm working on:
private String messageFormatter(String tMessage, Map<String, String> messageMap)
{
String formattedMsg = null;
Set<String> keyset = messageMap.keySet();
Iterator<String> keySetItr = keyset.iterator();
String msgkey = null;
boolean isFormatted = false;
while (keySetItr.hasNext())
{
msgkey = keySetItr.next();
if(t.contains(msgkey))
{
if(!isFormatted)
{
formattedMsg = tMessage.replaceAll("\\[", "").replaceAll("\\]", "");
formattedMsg = formattedMsg.replaceAll(msgkey, messageMap.get(msgkey));
isFormatted= true;
}else
{
formattedMsg = formattedMsg.replaceAll(msgkey, messageMap.get(msgkey));;
}
}else
{
formattedMsg=tMessage;
}
}
return formattedMsg;
}
The last else part is not right. Can anyone please help me with this. This code works fine for all the cases except when a matching key is not found in the map
is this idea ok for you?
instead of applying regex or extracting the stuff between [..], you could do some trick on your map side. e.g.
String s = "Hi [HandleKey], you have [Action]";
for(String k: yourMap.keySet()){
s=s.replaceAll("\\["+k+"\\]",yourMap.get(k));
}
You can do this with regex, here is a complete example code
public static void main(String[] args) {
String str = "Hi [HandleKey], you have [Action] ";
Hashtable<String, String> table = new Hashtable<String, String>();
table.put("HandleKey", "Peter");
Pattern pattern = Pattern.compile("\\[(\\w+)\\]");
Matcher matcher = pattern.matcher(str);
while (matcher.find()) {
String key = matcher.group(1);
if (table.containsKey(key)) {
str = str.replaceFirst("\\[" + key + "\\]", table.get(key));
}
}
System.out.println(str);
}
Output:
Hi Peter, you have [Action]
Note that this is more efficient than looping over the Map if the map size is already large or growing.
To handle when key not in map with minimal changes to what you have above try
formattedMsg.replaceAll(msgkey,
(messageMap.containsKey(msgKey) ? messageMap.get(msgkey) : "[" + msgKey + "]"));
but looking again I can see that you're iterating the set of keys from the messageMap so the issue of a key not appearing in the map doesn't arise?
There's also a reference to if(t.contains(msgKey))... but not sure what t is
if you want the text to contain the formatted [msgKey] when its no found then replacing all "[" & "]" seems the wrong way to start if you want to put them back in in some cases.
I'd look at #iTech's suggestion and get regex doing more for you
I have a string like this
STAR=20110209
00:01:01|PNAM=test_.xml|PNUM=480|SSTA=20110209
00:01:01|STRT=20110209
00:01:01|STOP=20110209 00:01:01|
and i want to extract values of few of the keys here.
like whats the value of PNAM and SSTA.
I want a regular expression that can provide the values of few of the keys and keys can be in any order.
Would something like this work for you?
String str = "STAR=20110209 00:01:01|PNAM=test_.xml|PNUM=480|SSTA=20110209 00:01:01|STRT=20110209 00:01:01|STOP=20110209 00:01:01";
String[] parts = str.split("\\|");
for (String part : parts)
{
String[] nameValue = part.split("=");
if (nameValue[0] == "somekey")
{
// ..
}
}
So, the way your problem is really isn't best solved with regular expressions. Instead, use split() like someone else has offered, but instead of having a crazy if loop, load everything into a map.
String str = "STAR=20110209 00:01:01|PNAM=test_.xml|PNUM=480|SSTA=20110209 00:01:01|STRT=20110209 00:01:01|STOP=20110209 00:01:01";
String[] parts = str.split("|");
Map<String, String> properties = new HashMap<String, String>();
for (String part : parts) {
String[] nameValue = part.split("=");
properties.put(nameValue[0], nameValue[1]);
}
Then all you have to do is, properties.get("PNUM")
Use this Java code:
String str = "STAR=20110209 00:01:01|PNAM=test_.xml|PNUM=480|SSTA=20110209 00:01:01|STRT=20110209 00:01:01|STOP=20110209 00:01:01|";
Pattern p = Pattern.compile("([^=]*)=([^|]*)\\|");
Matcher m = p.matcher(str);
String pnamVal = null, sstaVal = null;
while (m.find()) {
//System.out.println("Matched: " + m.group(1) + '=' + m.group(2));
if (m.group(1).equals("PNAM"))
pnamVal = m.group(2);
else if (m.group(1).equals("SSTA"))
sstaVal = m.group(2);
if (pnamVal != null && sstaVal != null)
break;
}
System.out.println("SSTA: " + sstaVal);
System.out.println("PNAM: " + pnamVal);
OUTPUT
SSTA: 20110209 00:01:01
PNAM: test_.xml