Reputation: 5471
I have the code below and I am testing it online here. Also had a look at this post. I am not the best at regular expressions. Basically I am using the stream API to spit a string containing no inner quotes(double/single). Its just a plain string which will never contain any quotes. I am trying to use the stream API to split up the string by commas into key value pairs and put it into a map. However the split is also splitting the requestparams=[id=4, isId=23] into this isId=23], requestparams=[id=4. its all messed up.
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
class Main {
public static void main(String[] args) {
String dataPts = "requestparams=[id=4, isId=23], requestid=12345678, channel=BATCH";
Map<String, String> reconstructedMap = Arrays.stream(dataPts.split(",")).map(s -> s.split("=",2)).collect(Collectors.toMap(s -> s[0], s -> s[1]));
System.out.println(reconstructedMap);
}
}
The above logic produces
{ requestid=12345678, isId=23], requestparams=[id=4, channel=BATCH}
. The [ ] and everything inside should remain as is. I should see {requestparams=[id=4, isId=23], requestid=12345678, channel=BATCH}
The solution I came up with is to clip out the requestparams=[id=4, isId=23] totally from the string using a regular expression as seen in the method below. Then add it back into the map at the end. Its seems messy and unusual.
Map<String,String> convertDataPtsFromStringToMap(String myData{
Pattern pattern = Pattern.compile("requestparams=(.*?])");//value alone [id=4, isId=23]
Matcher matcher = pattern.matcher(myData);
String reqParamsValue = "[]";
if(matcher.find()) {
reqParamsValue = matcher.group(1);
myData = myData.replaceAll("(requestparams.*?]),", "");//replace requestparams=[id=4, isId=23]
}
Map<String, String> reconstructedMap = Arrays.stream(dataPts.split(",")).map(s -> s.split("=",2)).collect(Collectors.toMap(s -> s[0], s -> s[1]));
reconstructedMap.put("requestparams", reqParamsValue);//add back the requestparams and its value to the resulting map
return reconstructedMap;
}
This requestparams will be the only value with [ ] and will not be changed, its just that it has to be in the string. That is whay i can strip it off and put it back in. But now my unit tests will require that property to always be in the string, which is not a problem. It just seems like too much. Looking for a more elegant solution.
Is there a better way using the Streams-Api?
Upvotes: 2
Views: 94
Reputation: 521093
Here is one approach using a formal Java regex pattern matcher:
String dataPts = "requestparams=[id=4, isId=23], requestid=12345678, channel=BATCH";
String pattern = "\\b([^=]+=(?:\\[[^]]+\\]|[^=,]+))(?:,\\s*|$)";
Pattern r = Pattern.compile(pattern);
Matcher m = r.matcher(dataPts);
while (m.find()) {
System.out.println(m.group(1));
}
This prints:
requestparams=[id=4, isId=23]
requestid=12345678
channel=BATCH
Here is an explanation of the regex logic:
\b
( capture the following
[^=]+ a LHS key
= =
(?:
\[[^]]+\] either a RHS term in square brackets (check for this first)
| OR
[^=,]+ another term not in brackets
)
) end capture
(?:,\\s*|$) then match either comma followed by whitespace, or the end of the string
If you wanted to populate a map with keys/values, then use:
String dataPts = "requestparams=[id=4, isId=23], requestid=12345678, channel=BATCH";
Map<String, String> map = new HashMap<>();
String pattern = "\\b([^=]+)=(\\[[^]]+\\]|[^=,]+)(?:,\\s*|$)";
Pattern r = Pattern.compile(pattern);
Matcher m = r.matcher(dataPts);
while (m.find()) {
map.put(m.group(1), m.group(2));
}
Upvotes: 3