In my below code, I am making a json string using gson:
private String generateData(Map<String, Map<Integer, Set<Integer>>> nodeTable, int i) {
JsonObject jsonObject = new JsonObject();
Set<Integer> pp = nodeTable.get("TEXTER").get(i);
Set<Integer> sp = nodeTable.get("PETER").get(i);
// my above pp and sp variables shows correct values with one space between numbers.
jsonObject.addProperty("description", "Hello. World");
jsonObject.add("data1", gson.toJsonTree(pp));
jsonObject.add("data2", gson.toJsonTree(sp));
System.out.println(jsonObject.toString());
return jsonObject.toString();
}
When I get my json string, I get it like this. As you can see after comma everything is next to each other without any spaces. I don't want like that.
{"description":"Hello. World.","data1":[0,273,546,819,1092,559],"data2":[816,1644,1368,276]}
I want to have one space between numbers in data1 and data2 variable as shown below:
{"description":"Hello. World.","data1":[0, 273, 546, 819, 1092, 559],"data2":[816, 1644, 1368, 276]}
Is this possible to do by any chance using gson or some other way?
This seems rather a cosmetic request with potential for bugs. Easiest way is probably using a regex:
jsonString = jsonString
.replaceAll("(\\d),(\\d)", "$1, $2")
.replaceAll("(\\d),(\\d)", "$1, $2")
The line above simply catches any digit + comma + digit sequence and adds a space between the two captured and restored digits. Since java catches matches only once, thus not allowing intersections, we're doing it two times here.
Alternative that is not so strict but doesn't require double replacing:
jsonString = jsonString.replaceAll(",(\\d)", ", $1")
The bug potential here is that this applies to the whole JSON string, not only encoded sets.
The right way™ would be to use a custom set formatter for GSON.
BTW, a map of maps cries for classes.
The easiest way to get space by using following methods like below
For 1:
jsonObject.add("data1", gson.toJsonTree(addSpaces(pp)));
jsonObject.add("data2", gson.toJsonTree(addSpaces(sp)))
For 2:
String string = addSpaceByRegEx(jsonObject.toString());
Add following methods in you class :
//1. if you need String value based spaces in json string
public Set<String> addSpaces(Set<Integer> integers) {
Set<String> strings = new HashSet<>();
for (Integer i : integers) {
strings.add(i.toString() + " ");
}
return strings;
}
//2. if you need space as in integer value in json string as your example
//This method add space by using regex
//Tested for String s = "{'description':'Hello. World.','data1':[0,273,546,819,1092,559],'data2':[816,1644,1368,276]}";
//In you example just replace following line
//System.out.println(jsonObject.toString()); by System.out.println(addSpaceByRegEx(jsonObject.toString()));
//See result, i think it work
public String addSpaceByRegEx(String jsonString) {
Pattern pattern = Pattern.compile(",[0-9]");
Matcher matcher = pattern.matcher(jsonString);
StringBuilder sb = new StringBuilder();
int prevIndex = 0;
while (matcher.find()) {
int startIndex = matcher.start();
int endIndex = matcher.end();
sb.append(jsonString.substring(prevIndex, startIndex + 1)).append(" ").append(jsonString.substring(startIndex + 1, endIndex));
prevIndex = endIndex;
}
sb.append(jsonString.substring(prevIndex, jsonString.length()));
return sb.toString();
}
Related
I have a HashMap<Integer, Double> which looks something similar like this:
{260=223.118,50, 261=1889,00, 262=305,70, 270=308,00}
From database I take a string that could look something like this:
String result = "(260+261)-(262+270)";
I want to change the string's values of 260, 261, 262... (which are always the same with the HashMap's keys) with the values so I could get a string like:
String finRes = "(223.118,50+1889,00)-(305,70+308,00)";
Also the string result can contain multiplication and division characters.
A simple regex solution here would be to match your input string against the pattern (\d+). This should yield all the integers in the arithmetic string. Then, we can lookup each match, converted to an integer, in the map to obtain the corresponding double value. Since the desired output is again a string, we have to convert the double back to a string.
Map<Integer, Double> map = new HashMap<>();
map.put(260, 223.118);
map.put(261, 1889.00);
map.put(262, 305.70);
map.put(270, 308.00);
String input = "(260+261)-(262+270)";
String result = input;
String pattern = "(\\d+)";
Pattern r = Pattern.compile(pattern);
Matcher m = r.matcher(input);
StringBuffer sb = new StringBuffer();
while (m.find()) {
m.appendReplacement(sb, String.valueOf(map.get(Integer.parseInt(m.group(1)))));
}
m.appendTail(sb);
System.out.println(sb.toString());
Output:
(223.118+1889.0)-(305.7+308.0)
Demo here:
Rextester
here is an explained solution:
// your hashmap that contains data
HashMap<Integer,Double> myHashMap = new HashMap<Integer,Double>();
// fill your hashmap with data ..
..
// the string coming from the Database
String result = "(260+261)-(262+270)";
// u will iterate all the keys of your map and replace each key by its value
for(Integer n : myHashMap.keySet()) {
result = result.replace(n,Double.toString(myHashMap.get(n)));
}
// the String variable 'result' will contains the new String
Hope it helps :)
I want to parse the following and store it as a new string, with the condition that mawi is stored and everything else is removed.
<ns0:Assignee>mawi - Manfred Wilson</ns0:Assignee>
One solution I suppose could be a substring starting with the first character after the first > and ending two characters before the first -. All the data is identical. The result is a String with value mawi.
String initial = "<ns0:Assignee>mawi - Manfred Wilson</ns0:Assignee>";
String substring = initial.substring(example.indexOf(">"));
Not sure where to go from here... Any thoughts?
Although the below code do the trick, I suggest you to use Jsoup or XML Parse if you are processing multiple strings like this
Pattern pattern = Pattern.compile("<ns0:Assignee>(.+?)</ns0:Assignee>");
Matcher matcher = pattern.matcher("<ns0:Assignee>mawi - Manfred Wilson</ns0:Assignee>");
matcher.find();
String result = matcher.group(1);
String finalString = result.split(" - ")[0];
System.out.println(finalString); // mawi
If all the strings are built like your example string, you could go with this:
initial.substring(initial.indexOf('>') + 1, initial.indexOf(' '));
Note the + 1 at the start index.
When your Strings are more complicated, I would recommend either using a library for working with XML or using Regular Expressions.
So now you got substring which is equal to: >mawi - Manfred Wilson</ns0:Assignee>.
Now, you can substring your substring again to find only mawi, like this;
String initial = "<ns0:Assignee>mawi - Manfred Wilson</ns0:Assignee>";
String midSub = initial.substring(initial.indexOf('>'));
String finalSub = midSub.substring(1, midSub.indexOf(' ')); // 1 because we still have `>`
System.out.println(finalSub);
Or, one liner:
String finalSub = initial.substring(initial.indexOf('>')+1, initial.indexOf(' '));
show this:
String s = "<ns0:Assignee>mawi - Manfred Wilson</ns0:Assignee>";
s = s.substring(s.indexOf("<ns0:Assignee>")+"<ns0:Assignee>".length(), s.indexOf("</ns0:Assignee>"));
public class string {
public static void main(String[] args) {
String s = "<ns0:Assignee>mawi - Manfred Wilson</ns0:Assignee>";
s = s.substring(14, 18);
System.out.println(s);
}
}
There's a string
String str = "ggg;ggg;nnn;nnn;aaa;aaa;xxx;xxx;";
How do I split it into strings like this
"ggg;ggg;"
"nnn;nnn;"
"aaa;aaa;"
"xxx;xxx;"
???????
Using Regex
String input = "ggg;ggg;nnn;nnn;aaa;aaa;xxx;xxx;";
Pattern p = Pattern.compile("([a-z]{3});\\1;");
Matcher m = p.matcher(input);
while (m.find())
// m.group(0) is the result
System.out.println(m.group(0));
Will output
ggg;ggg;
nnn;nnn;
aaa;aaa;
xxx;xxx;
I assume that the you only want to check if the last segment is similar and not every segment that has been read.
If that is not the case then you would probably have to use an ArrayList instead of a Stack.
I also assumed that each segment has the format /([a-z])\1\1/.
If that is not the case either then you should change the if statement with:
(stack.peek().substring(0,index).equals(temp))
public static Stack<String> splitString(String text, char split) {
Stack<String> stack = new Stack<String>();
int index = text.indexOf(split);
while (index != -1) {
String temp = text.substring(0, index);
if (!stack.isEmpty()) {
if (stack.peek().charAt(0) == temp.charAt(0)) {
temp = stack.pop() + split + temp;
}
}
stack.push(temp);
text = text.substring(index + 1);
index = text.indexOf(split);
}
return stack;
}
Split and join them.
public static void main(String[] args) throws Exception {
String data = "ggg;ggg;nnn;nnn;aaa;aaa;xxx;xxx;";
String del = ";";
int splitSize = 2;
StringBuilder sb = new StringBuilder();
for (Iterable<String> iterable : Iterables.partition(Splitter.on(del).split(data), splitSize)) {
sb.append("\"").append(Joiner.on(del).join(iterable)).append(";\"");
}
sb.delete(sb.length()-3, sb.length());
System.out.println(sb.toString());
}
Ref : Split a String at every 3rd comma in Java
Use split with a regex:
String data="ggg;ggg;nnn;nnn;aaa;aaa;xxx;xxx;";
String [] array=data.split("(?<=\\G\\S\\S\\S;\\S\\S\\S);");
S: A non-whitespace character
G: last match/start of string, think of it of a way to skip delimiting if the
previous string matches current one.
?<=:positive look-behind will match semicolon which has string behind it.
Some other answer, that only works given your specific example input.
You see, in your example, there are two similarities:
All patterns seem to have exactly three characters
All patterns occur exactly twice
In other words: if those two properties are really met for all your input, you could avoid splitting - as you know exactly what to find in each position of your string.
Of course, following the other answers for "real" splitting are more flexible; but (theoretically), you could just go forward and do a bunch of substring calls in order to directly access all elements.
I have a question about how to replace String when matched character found. In this case, i read java file that contains variable which marked with underscore. Here the java file:
public int[][] initArray(int rows, int cols, int init_value)
{
int[][] _bb = (int[][])null;
if ((rows > 1) && (cols > 1)) {
_bb = new int[rows][cols];
for (int _ii = 0; _ii < rows; _ii++) {
for (int _ee = 0; _ee < cols; _ee++) {
_bb[_ii][_ee] = init_value;
}
}
} else {
warning("Array length must be greater than zero!");
}
return _bb;
}
All of variable that contain underscore will be replaced with generate string. Well, then this is the code that i have used to read that file and replace matched string:
HashMap<String, String> map = new HashMap<String, String>();
if (line.contains(" _") && line.contains(";")) {
String get = varname(line);
RandomString r = new RandomString();
String[] split = get.split("\\s+");
String gvarname = split[0];
ss = "_"+gvarname;
map.put(ss, "l"+r.generateRandomString());
for(String key: map.keySet()){
if(line.contains(key)){
line = line.replace(key, map.get(key));
}
}
Then, this is a method to get an index of variable name:
String varname(String str){
int startIdx = str.indexOf("_");
int endIdx = str.indexOf(';');
String content = str.substring(startIdx + 1, endIdx);
return content;
}
Actually above code is working and replace some variables name, but some character noted matched when i put space example _bb[_ii] is not working, but _bb[ _ii ] is working. I don't know how, help me!
Thanks
Use regex to recognize the entire variable, here using \b to find word boundaries.
public class Obfuscate {
private static final Pattern VAR_PATTERN = Pattern.compile("\\b_(\\w+)\\b");
private final Map<String, String> renames = new HashMap<>();
public String obfuscate(String sourceCode) {
StringBuffer buf = new StringBuffer(sourceCode.length() + 100);
Matcher m = VAR_PATTERN.matcher(sourceCode);
while (m.find()) {
String var = m.group(1);
String newVar = renames.get(var);
if (newVar == null) {
newVar = randomVar();
renames.put(var, newVar);
}
m.appendReplacement(buf, newVar);
}
m.appendTail(buf);
return buf.toString();
}
}
A map is needed to match the same old variable to the same new name.
A Set<String> of new names might be needed to check that the generated name does not repeat.
Your approach of doing a replaceAll of the same var is fine too, but requires reading all. The method above can be repeated (say per line), hence the map as field.
In your first if-statement you check if the string contains " _" (an underscore with a leading space).
If in the following line of your source-java-file
_bb[_ii][_ee] = init_value;
_bb... is indented with tabulators, <tab>_bb will not match <space>_bb. There is no leading space before _ii and _ee either, so the if returns false.
If you put a space between [ and _ii, you find a match for <space>_ii and your if results in true and executes your replacement code.
If you are sure that there will be no other use of an underscore in your source text other than as a replacement indicator, you can simply remove the space from your if-condition and use line.contains("_") instead.
Btw: Are you sure that you want to check that the line must contain a ; aswell? What if your source text contains a line like while(_xx==true) {?
Also, because of
String[] split = get.split("\\s+");
String gvarname = split[0];
your code is not able to split a line like _bb[_ii][_ee] correctly (and even if it would be, because of split[0] you would only replace the first identifier you found, subsequent ones would be ignored). Your split searches for spaces and the source line doesn't contain any. Again, you could probably change this and split for underscores (this would return an array containing bb[, ii][ and ee]) and then loop every returned array element until you find the first character that can't be part of your variable identifier (e.g. until the first non-alphanumeric character).
An _ plus the part of the array element up to that non-alphanumeric character is then the identifier that you want to replace.
I have a requirement to get the substring of a string based on a condition.
String str = "ABC::abcdefgh||XYZ::xyz";
If input is "ABC", check if it contains in str and if it presents then it should print abcdefgh.
In the same way, if input is "XYZ", then it should print xyz.
How can i achieve this with string manipulation in java?
If I've guessed the format of your String correctly, then you could split it into tokens with something like this:
String[] tokens = str.split("||");
for(String token : tokens)
{
// Cycle through each token.
String key = token.split("::")[0];
String value = token.split("::")[1];
if(key.equals(input))
{
// input being the user's typed in value.
return value;
}
}
But let's have a think for a minute. Why keep this in a String, when a HashMap is a much cleaner solution to your problem? Stick the String into a config file, and on load,
some code can perform a similar task:
Map<String, String> inputMap = new HashMap<String, String>();
String[] tokens = str.split("||");
for(String token : tokens)
{
// Cycle through each token.
String key = token.split("::")[0];
String value = token.split("::")[1];
inputMap.put(key, value);
}
Then when the user types something in, it's as easy as:
return inputMap.get(input);
The idea is that, you should split your string with the delimiters of "::" and "||" , i.e. whichever of them is encountered it will be treated as a delimiter. So, the best way for achieving that is using regular expressions, I think.
String str = "ABC::abcdefgh||XYZ::xyz";
String[] parts = str.split("[::]|[/||]");
Map<String, String> map = new HashMap<String, String>();
for (int i = 0; i < parts.length - 2; i += 4) {
if (!parts[i].equals("")) {
map.put(parts[i], parts[i + 2]);
}
}
Short and concise, your code is ready. The for loop seems weird, if anyone comes up with a better regex for splitting (to get rid of the empty strings), it will become cleaner. I'm not a regex expert, so any suggestions are welcome.
Use the contains method to see if it has the sub string: http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#contains%28java.lang.CharSequence%29
You could do it as follows:
String[] parts = st.split("||");
if (parts[0].startsWith("ABC")) {
String[] values = parts[0].split("::");
System.out.println(values[1]);
} else {
if (parts[1].startsWith("XYZ") {
String[] values = parts[0].split("::");
System.out.println(values[1]);
}
}
The above code will check first if ABC is there. If yes, it will print the result and then stop. If not, it will check the second section of the code to see if it starts with XYZ and then print the result. You can change it to suit your needs.