I'm struggling to escape the double quotation marks when I try to convert my Map to String
//iterate through map and append to array
StringBuilder mapAsString = new StringBuilder("{");
for (String key : billingDetails.keySet()) {
mapAsString.append(key + ":" + billingDetails.get(key) + ", ");
}
mapAsString.delete(mapAsString.length()-2, mapAsString.length()).append("}");
String bdResult = mapAsString.toString();
Current output
"position": [
"{2018:Element3, 2012:Element2, 2010:Element1}"
Expected output
"position": [
"{"2018":"Element3", "2012":"Element2", "2010":"Element1"}"
Following method appends the contents of the Map to String however I can't seem to figure out how to escape the quotation marks so that the expected output is correct
mapAsString.append(key + ":" + billingDetails.get(key) + ", ");
Escaping characters in java has always been somewhat of a difficulty for me and I would appreciate it if someone with a wider knowledge would help me out
Cheers and thanks
Escape the quotes with an backslash
mapAsString.append("\"" + key + "\":\"" + billingDetails.get(key) + "\", ");
Related
I want to get all the message data. Such that it should look for message and all the data between curly braces of the parent message. With the below pattern, I am not getting all parent body.
String data = "syntax = \"proto3\";\r\n" +
"package grpc;\r\n" +
"\r\n" +
"import \"envoyproxy/protoc-gen-validate/validate/validate.proto\";\r\n" +
"import \"google/api/annotations.proto\";\r\n" +
"import \"google/protobuf/wrappers.proto\";\r\n" +
"import \"protoc-gen-swagger/options/annotations.proto\";\r\n" +
"\r\n" +
"message Acc {\r\n" +
" message AccErr {\r\n" +
" enum Enum {\r\n" +
" UNKNOWN = 0;\r\n" +
" CASH = 1;\r\n" +
" }\r\n" +
" }\r\n" +
" string account_id = 1;\r\n" +
" string name = 3;\r\n" +
" string account_type = 4;\r\n" +
"}\r\n" +
"\r\n" +
"message Name {\r\n" +
" string firstname = 1;\r\n" +
" string lastname = 2;\r\n" +
"}";
List<String> allMessages = new ArrayList<>();
Pattern pattern = Pattern.compile("message[^\\}]*\\}");
Matcher matcher = pattern.matcher(data);
while (matcher.find()) {
String str = matcher.group();
allMessages.add(str);
System.out.println(str);
}
}
I am expecting response like below in my array list of string with size 2.
allMessage.get(0) should be:
message Acc {
message AccErr {
enum Enum {
UNKNOWN = 0;
CASH = 1;
}
}
string account_id = 1;
string name = 3;
string account_type = 4;
}
and allMessage.get(1) should be:
message Name {
string firstname = 1;
string lastname = 2;
}
First remove the input prior to "message" appearing at the start of the line, then split on newlines followed by "message" (include the newlines in the split so newlines that intervene parent messages are consumed):
String[] messages = data.replaceAll("(?sm)\\A.*?(?=message)", "").split("\\R+(?=message)");
See live demo.
If you actually need a List<String>, pass that result to Arrays.asList():
List<String> = Arrays.asList(data.replaceAll("(?sm)\\A.*?(?=message)", "").split("\\R+(?=message)"));
The first regex matches everything from start up to, but not including, the first line that starts with message, which is replaced with a blank (ie deleted). Breaking the down:
(?sm) turns on flags s, which makes dot also match newlines, and m, which makes ^ and $ match start and end of each line
\\A means the very start of input
.*? .* means any quantity of any character (including newline as per the s flag being set), but adding ? makes this reluctant, so it matches as few characters as possible while still matching
(?=^message) is a look ahead and means the following characters are a start of a line then "message"
See regex101 live demo for a thorough explanation.
The split regex matches one or more line break sequences when they are followed by "message":
\\R+ means one or more line break sequences (all OS variants)
(?=message) is a look ahead and means the following characters are "message"
See regex101 live demo for a thorough explanation.
Try this for your regex. It anchors on message being the start of a line, and uses a positive lookahead to find the next message or the end of messages.
Pattern.compile("(?s)\r\n(message.*?)(?=(\r\n)+message|$)")
// or
Pattern.compile("(?s)\r?\n(message.*?)(?=(\r?\n)+message|$)")
No spliting, parsing, or managing nested braces either :)
https://regex101.com/r/Wa2xxx/1
I am struggling a bit with splitting a string.
Here is an example of an input and the correct output I want:
Input: "Hope you're doing well! I am doing ok. " <--- A few spaces after the period
Output:
[Hope, " ", you're, " ", doing, well, "!" , " ", "I", " ",
"am", " ", "doing", " ", "ok", "." , " ", " ", " ", " ", " "]
I want an output that splits all the words into it's own index (even if it includes an apostrophe). Also, I want all the spaces and punctuation(?, !, ., " ") to have their own index in the array.
Here's what I've tried: I have taken a string message and used the split function. I have used a regex which is giving me almost the correct output, but it's not accounting for extra spaces after the period.
The regex I used:
"\\b |(?=\\p{Punct})|(?<=\\p{Punct}) | "
Anyone have any suggestions? Thank you for your time.
Here is a way to do it but it is rather unorthodox.
String str = "Hope you're doing well! I am doing ok. ";
Establish a regex for all the punctuation, spaces, etc you want using a capture group.
String regex = "([!\\s\\.])";
Then replace each occurrence of those surrounded by a non-relevant character. In this case I used a #. You could actually use several characters together as a split delimiter.
Then split on that character.
String[] tokens = str.replaceAll(regex, "#$1#").split("#");
System.out.println(Arrays.toString(tokens));
Prints
[Hope, , you're, , doing, , well, !, , , I, , am, , doing, , ok, ., , ]
You can get rid of the empty strings ("") as follows:
tokens = Arrays.stream(tokens).filter(s->!s.isEmpty()).toArray(String[]::new);
First you need to define what constitutes the characters of a "word", and anything else should become a separate token. Here I've defined word-characters as letters, numbers, apostrophes, and dashes, so the separate tokens are anything but those:
[^\p{L}\p{N}'-]
Then you build a regex using zero-with positive lookahead and lookbehind for the non-word characters, with a little extra to make sure we don't do a zero-width match at beginning or end of input.
(?<!^)(?=[^\p{L}\p{N}'-])|(?<=[^\p{L}\p{N}'])(?!$)
As Java code, that would be:
String input = "Hope you're doing well! I am doing ok. ";
String regex = "(?<!^)(?=[^\\p{L}\\p{N}'-])|(?<=[^\\p{L}\\p{N}'])(?!$)";
String[] tokens = input.split(regex);
System.out.println(Arrays.stream(tokens).map(s -> '"' + s + '"')
.collect(Collectors.joining(", ", "[", "]")));
Output
["Hope", " ", "you're", " ", "doing", " ", "well", "!", " ", "I", " ",
"am", " ", "doing", " ", "ok", ".", " ", " ", " ", " ", " "]
One of my webservice return below Java string:
[
{
id=5d93532e77490b00013d8862,
app=null,
manufacturer=pearsonEducation,
bookUid=bookIsbn,
model=2019,
firmware=[1.0],
bookName=devotional,
accountLinking=mandatory
}
]
I have the equivalent Java object for the above string. I would like to typecast or convert the above java string into Java Object.
I couldn't type-cast it since it's a String, not an object. So, I was trying to convert the Java string to JSON string then I can write that string into Java object but no luck getting invalid character "=" exception.
Can you change the web service to return JSON?
That's not possible. They are not changing their contracts. It would be super easy if they returned JSON.
The format your web-service returns has it's own name HOCON. (You can read more about it here)
You do not need your custom parser. Do not try to reinvent the wheel.
Use an existing one instead.
Add this maven dependency to your project:
<dependency>
<groupId>com.typesafe</groupId>
<artifactId>config</artifactId>
<version>1.3.0</version>
</dependency>
Then parse the response as follows:
Config config = ConfigFactory.parseString(text);
String id = config.getString("id");
Long model = config.getLong("model");
There is also an option to parse the whole string into a POJO:
MyResponsePojo response = ConfigBeanFactory.create(config, MyResponsePojo.class);
Unfortunately this parser does not allow null values. So you'll need to handle exceptions of type com.typesafe.config.ConfigException.Null.
Another option is to convert the HOCON string into JSON:
String hoconString = "...";
String jsonString = ConfigFactory.parseString(hoconString)
.root()
.render(ConfigRenderOptions.concise());
Then you can use any JSON-to-POJO mapper.
Well, this is definitely not the best answer to be given here, but it is possible, at least…
Manipulate the String in small steps like this in order to get a Map<String, String> which can be processed. See this example, it's very basic:
public static void main(String[] args) {
String data = "[\r\n"
+ " {\r\n"
+ " id=5d93532e77490b00013d8862, \r\n"
+ " app=null,\r\n"
+ " manufacturer=pearsonEducation, \r\n"
+ " bookUid=bookIsbn, \r\n"
+ " model=2019,\r\n"
+ " firmware=[1.0], \r\n"
+ " bookName=devotional, \r\n"
+ " accountLinking=mandatory\r\n"
+ " }\r\n"
+ "]";
// manipulate the String in order to have
String[] splitData = data
// no leading and trailing [ ] - cut the first and last char
.substring(1, data.length() - 1)
// no linebreaks
.replace("\n", "")
// no windows linebreaks
.replace("\r", "")
// no opening curly brackets
.replace("{", "")
// and no closing curly brackets.
.replace("}", "")
// Then split it by comma
.split(",");
// create a map to store the keys and values
Map<String, String> dataMap = new HashMap<>();
// iterate the key-value pairs connected with '='
for (String s : splitData) {
// split them by the equality symbol
String[] keyVal = s.trim().split("=");
// then take the key
String key = keyVal[0];
// and the value
String val = keyVal[1];
// and store them in the map ——> could be done directly, of course
dataMap.put(key, val);
}
// print the map content
dataMap.forEach((key, value) -> System.out.println(key + " ——> " + value));
}
Please note that I just copied your example String which may have caused the line breaks and I think it is not smart to just replace() all square brackets because the value firmware seems to include those as content.
In my opinion, we split the parse process in two step.
Format the output data to JSON.
Parse text by JSON utils.
In this demo code, i choose regex as format method, and fastjson as JSON tool. you can choose jackson or gson. Furthermore, I remove the [ ], you can put it back, then parse it into array.
import com.alibaba.fastjson.JSON;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class SerializedObject {
private String id;
private String app;
static Pattern compile = Pattern.compile("([a-zA-Z0-9.]+)");
public static void main(String[] args) {
String str =
" {\n" +
" id=5d93532e77490b00013d8862, \n" +
" app=null,\n" +
" manufacturer=pearsonEducation, \n" +
" bookUid=bookIsbn, \n" +
" model=2019,\n" +
" firmware=[1.0], \n" +
" bookName=devotional, \n" +
" accountLinking=mandatory\n" +
" }\n";
String s1 = str.replaceAll("=", ":");
StringBuffer sb = new StringBuffer();
Matcher matcher = compile.matcher(s1);
while (matcher.find()) {
matcher.appendReplacement(sb, "\"" + matcher.group(1) + "\"");
}
matcher.appendTail(sb);
System.out.println(sb.toString());
SerializedObject serializedObject = JSON.parseObject(sb.toString(), SerializedObject.class);
System.out.println(serializedObject);
}
}
I came across this unusual error today. Can anyone explain me what I am doing wrong. Below is the code:
AreStringsPermuted checkStringPerObj = new AreStringsPermuted();
String[] inputStrings = {"siddu$isdud", "siddu$siddarth", "siddu$sidde"};
for(String inputString : inputStrings){
String[] stringArray = inputString.split("$");
if(checkStringPerObj.areStringsPermuted(stringArray[0],stringArray[1]))
System.out.println("Strings : " + stringArray[0] + " ," + stringArray[1] + " are permuted");
else
System.out.println("Strings : " + stringArray[0] + " ," + stringArray[1] + " are not permuted");
}
The above code errors out at when i try to split the string. For some reason split does not work when I try to divide each string using "$". Can any one explain me what I am doing wrong here?
Below is the error message:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 1
at arraysAndStrings.TestClass.checkStringsPermuted(TestClass.java:24)
at arraysAndStrings.TestClass.main(TestClass.java:43)
String.split() takes a regular expression, so you need to quote strings that contain characters that have special meanings in regular expressions.
String regularExpression = Pattern.quote("$");
for (String inputString : inputStrings) {
String[] stringArray = inputString.split(regularExpression);
String.split( ) uses regex partern and $ has special meaning in regex(the end of line).
In your case, use "\$" instead of "$".
String []arrayString = inputString.split("\\$");
For more information,
http://docs.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html
I'm parsing some folder names here. I have a program that lists subfolders of a folder and parses folder names.
For example, one folder could be named something like this:
"Folder.Name.1234.Some.Info.Here-ToBeParsed"
and I would like to parse it so name would be "Folder Name". At the moment I'm first using string.replaceAll() to get rid of special characters and then there is this 4-digit sequence. I would like to split string on that point. How can I achieve this?
Currently my code looks something like this:
// Parsing string if regex p matches folder's name
if(b) {
//System.out.println("Folder: \" " + name + "\" contains special characters.");
String result = name.replaceAll("[\\p{P}\\p{S}]", " "); // Getting rid of all punctuations and symbols.
//System.out.println("Parsed: " + name + " > " + result);
// If string matches regex p2
if(b2) {
//System.out.println("Folder: \" " + result + "\" contains release year.");
String parsed_name[] = result.split("20"); // This is the line i would like to split when 4-digits in row occur.
//System.out.println("Parsed: " + result + " > " + parsed_name[0]);
movieNames.add(parsed_name[0]);
}
Or maybe there is even easier way to do this? Thanks in advance!
You should keep it simple like this:
String name = "Folder.Name.1234.Some.Info.Here-ToBeParsed";
String repl = name.replaceFirst( "\\.\\d{4}.*", "" ).
replaceAll( "[\\p{P}\\p{S}&&[^']]+", " " );
//=> Folder Name
replaceFirst is removing everything after a DOT and 4 digits
replaceAll is replacing all punctuation and space (except apostrophe) by a single space