REGEX to replace numbers with String - java

I have a String as below:
((((1 OR 2) AND 3) OR 11) AND 23)
I want to replace numbers with String values.
I am new to regex and unable to figure out how to replace numbers lying within a range.

Here is my code to resolve your problem. My poor regex knowlodge was not enough to resolve by only using regex.
public static void main(String[] args)
{
String temp = "(X)+|";
String regex = "";
String text = "((((1 OR 2) AND 3) OR 11) AND 23)";
Map<String, String> numberToString = new TreeMap<>((o1, o2) -> Integer.valueOf(o2) - Integer.valueOf(o1));
numberToString.put("3", "THREE");
numberToString.put("2", "TWO");
numberToString.put("1", "ONE");
numberToString.put("11", "ELEVEN");
numberToString.put("23", "TWENTYTHREE");
for(String number : numberToString.keySet()){
regex = regex + temp.replace("X", number);
}
regex = regex.substring(0, regex.lastIndexOf('|'));
Set<String> allMatches = new TreeSet<>((o1, o2) -> Integer.valueOf(o2) - Integer.valueOf(o1));
Matcher m = Pattern.compile(regex).matcher(text);
while (m.find()) {
allMatches.add(m.group());
}
for (String match : allMatches) {
if (numberToString.get(match) != null)
text = text.replaceAll(match, numberToString.get(match));
}
System.out.println(text);
System.out.println(regex);
}

Use str.replaceAll(1, "one"); function

Related

Java string replace regex pattern with evaluated key

I have an input string like this
I want to go to {places} where {things} are happening.
The values for {places} and {things} are computed lazily (i.e. first i find out what all keys needs to be replaced and then compute the values for them, and then replace them in the original string).
I am able to find out all the keys and removing them using the below code.
public class Temp {
private static final Pattern betweenCurlyBracesMatcher = Pattern.compile("\\{(.*?)\\}");
public static void main(String args[]) {
System.out.println(resolve2("hello {world} from {here}"));
}
public static String resolve2(String input) {
Map<String, String> keyValueMap = new HashMap<>();
Matcher matcher = betweenCurlyBracesMatcher.matcher(input);
while (matcher.find()) {
String key = matcher.group(1);
if (!keyValueMap.containsKey(key)) {
keyValueMap.put(key, computeValueForKey(key));
}
}
for (Map.Entry<String, String> entry : keyValueMap.entrySet()) {
input = input.replace("{" + entry.getKey() + "}", entry.getValue()); // << ugly code here
}
return input;
}
private static String computeValueForKey(String key) {
return "new" + key;
}
}
but I am not happy with
input = input.replace("{" + entry.getKey() + "}", entry.getValue());
because it means whenever i change my regex i will have to update this logic. Is there a more elegant solution to this problem.
input hello {world} from {here}
output hello newworld from newhere
input I want to go to {places} where {things} are happening.
output I want to go to newplaces where newthings are happening.
You should make use of the Matcher#appendReplacement and Matcher#appendTail APIs here:
Map<String, String> keyValueMap = new HashMap<>();
keyValueMap.put("places", "to America");
keyValueMap.put("things", "events");
String input = "I want to go to {places} where {things} are happening.";
Pattern pattern = Pattern.compile("\\{(.*?)\\}");
Matcher matcher = pattern.matcher(input);
StringBuffer buffer = new StringBuffer();
while(matcher.find()) {
matcher.appendReplacement(buffer, keyValueMap.get(matcher.group(1)));
}
matcher.appendTail(buffer);
System.out.println(buffer.toString());
This prints:
I want to go to to America where events are happening.
We can use matcher.group(0) with returns entire matched string
public class Temp {
private static final Pattern betweenCurlyBracesMatcher = Pattern.compile("\\{(.*?)\\}");
public static void main(String args[]) {
System.out.println(resolve2("hello {world} from {here}"));
}
public static String resolve2(String input) {
Map<String, String> keyValueMap = new HashMap<>();
Matcher matcher = betweenCurlyBracesMatcher.matcher(input);
while (matcher.find()) {
String keyBetweenBraces = matcher.group(1);
String keyWithBraces = matcher.group(0);
if (!keyValueMap.containsKey(keyWithBraces)) {
keyValueMap.put(keyWithBraces, computeValueForKey(keyBetweenBraces));
}
}
for (Map.Entry<String, String> entry : keyValueMap.entrySet()) {
input = input.replace(entry.getKey(), entry.getValue());
}
return input;
}
private static String computeValueForKey(String key) {
return "new" + key;
}
}

How do you add a delimiter in a given String format in Java?

I have the following String
"12:00:00, 2:30:003:45:00,23:45:00";
I have to update the string to use the following format:
"12:00:00, 2:30:00 |3:45:00,23:45:00 ";
I am able to split each string, but I do not know how to generate the required format. Here is the code I've written so far:
final String s = "12:00:00, 2:30:003:45:00,23:45:00";
final Pattern p = Pattern.compile("\\s*(\\d+:\\d\\d:\\d\\d)");
final Matcher m = p.matcher(s);
final List<String> tokens = new ArrayList<String>();
while (m.find()) {
tokens.add(m.group(1));
}
for (String tok : tokens) {
System.out.printf("[%s]%n", tok);
}
How about this:
final String string = "12:00:00, 2:30:003:45:00,23:45:00";
final Pattern pattern = Pattern.compile("\\s*(\\d+:\\d\\d:\\d\\d)");
final Matcher matcher = pattern.matcher(string);
final List<String> tokens = new ArrayList<String>();
while (matcher.find()) {
tokens.add(matcher.group(1));
}
System.out.println("tokens = " + tokens);
StringBuilder formattedString = new StringBuilder();
formattedString.append(tokens.get(0));
for (int i = 1; i < tokens.size(); i++) {
if (i % 2 == 0) {
formattedString.append(" | ");
} else {
formattedString.append(", ");
}
formattedString.append(tokens.get(i));
}
System.out.println(formattedString);
Edit: I've updated it to use a for loop when constructing the formatted string based on the comments I've read.
If you want to add | after two dates separated by comma your code can look like
final String s = "12:00:00, 2:30:003:45:00,23:45:00";
final Pattern p = Pattern.compile("(\\d+:\\d\\d:\\d\\d)\\s*,\\s*(\\d+:\\d\\d:\\d\\d)");
final Matcher m = p.matcher(s);
String result = m.replaceAll("$0|");
Or even
String result = s.replaceAll("?:\\d+:\\d\\d:\\d\\d),\\s*(?:\\d+:\\d\\d:\\d\\d)","$0|");
$0 refers to group 0 which holds entire match.
result is 12:00:00, 2:30:00|3:45:00,23:45:00|
You may consider this replaceAll method using lookarounds:
final String s = "12:00:00, 2:30:003:45:00,23:45:00";
System.out.printf("%s%n", s.replaceAll("(?<=:\\d\\d)(?=(?::\\d{1,2}|$))", "|"));
// 12:00|:00, 2:30|:003:45|:00,23:45|:00|

Does not work Regex for multiple string split in java?

I want to split string with multiple string delimiter.
For example :
String is "abc[11]xyz[86]pqr[87]sdv[11]adf[86]fgr[87]fadggthy"
Output :
abc
xyz
pqr
sdv
adf
fgr
fadggthy
I want to split string by "[11]" , "[86]" , "[87]"
Tried following code but does not work.
void testSplit() {
StringBuilder message = new StringBuilder("abc[11]xyz[86]pqr[87]sdv[11]adf[86]fgr[87]fadggthy");
Map<String, String> replaceStringMap = new HashMap();
replaceStringMap.put("\\\\[11\\\\]", "11");
replaceStringMap.put("\\\\[86\\\\]", "86");
replaceStringMap.put("\\\\[87\\\\]", "87");
String starter = "(";
String middle = ")|(";
String end = ")";
Set<String> keySet = replaceStringMap.keySet();
boolean isFirst = true;
StringBuilder regex = new StringBuilder(starter);
Iterator<String> itr = keySet.iterator();
while(itr.hasNext()) {
String string = itr.next();
if(itr.hasNext()) {
regex.append(string);
regex.append(middle);
} else {
regex.append(string);
regex.append(end);
}
}
System.out.println(regex.toString());
String[] strings = message.toString().split(regex.toString());
for(String s : strings) {
System.out.println(s);
}
}
Output :
(\\[87\\])|(\\[11\\])|(\\[86\\])
abc[11]xyz[86]pqr[87]sdv[11]adf[86]fgr[87]fadggthy
Output:abc[11]xyz[86]pqr[87]sdv[11]adf[86]fgr[87]fadggthy
Expected Output:
abc
xyz
pqr
sdv
adf
fgr
fadggthy
Below Code works :
String regex = "(\\[87\\])|(\\[11\\])|(\\[86\\])";
Here if i hardcode regex then it works but when i generate regex dynamically by reading value from map then it does not work.
Problem is that i can't generate regex at dynamic level.
You have an extra pair of \ in your delimeters.
Given this:
StringBuilder message = new StringBuilder("abc[11]xyz[86]pqr[87]sdv[11]adf[86]fgr[87]fadggthy");
Map<String, String> replaceStringMap = new HashMap();
replaceStringMap.put("\\[11\\]", "11");
replaceStringMap.put("\\[86\\]", "86");
replaceStringMap.put("\\[87\\]", "87");
String starter = "(";
String middle = ")|(";
String end = ")";
Set<String> keySet = replaceStringMap.keySet();
boolean isFirst = true;
StringBuilder regex = new StringBuilder(starter);
Iterator<String> itr = keySet.iterator();
while (itr.hasNext()) {
String string = itr.next();
if (itr.hasNext()) {
regex.append(string);
regex.append(middle);
} else {
regex.append(string);
regex.append(end);
}
}
System.out.println(regex.toString());
String[] strings = message.toString().split(regex.toString());
for (String s : strings) {
System.out.println(s);
}
}
It yields this:
(\[86\])|(\[87\])|(\[11\])
abc
xyz
pqr
sdv
adf
fgr
fadggthy
A general solution, for any value between [] considered as separator:
String test = abc[11]xyz[86]pqr[87]sdv[11]adf[86]fgr[87]fadggthy
String r = "(\\[[^\\]]*\\])"
for(String part : test.split(r)) println(part)
> abc
> xyz
> pqr
> sdv
> adf
> fgr
> fadggthy

Word count with java 8

I am trying to implement a word count program in java 8 but I am unable to make it work. The method must take a string as parameter and returns a Map<String,Integer>.
When I am doing it in old java way, everthing works fine. But when I am trying to do it in java 8, it returns a map where the keys are the empty with the correct occurrences.
Here is my code in a java 8 style :
public Map<String, Integer> countJava8(String input){
return Pattern.compile("(\\w+)").splitAsStream(input).collect(Collectors.groupingBy(e -> e.toLowerCase(), Collectors.reducing(0, e -> 1, Integer::sum)));
}
Here is the code I would use in a normal situation :
public Map<String, Integer> count(String input){
Map<String, Integer> wordcount = new HashMap<>();
Pattern compile = Pattern.compile("(\\w+)");
Matcher matcher = compile.matcher(input);
while(matcher.find()){
String word = matcher.group().toLowerCase();
if(wordcount.containsKey(word)){
Integer count = wordcount.get(word);
wordcount.put(word, ++count);
} else {
wordcount.put(word.toLowerCase(), 1);
}
}
return wordcount;
}
The main program :
public static void main(String[] args) {
WordCount wordCount = new WordCount();
Map<String, Integer> phrase = wordCount.countJava8("one fish two fish red fish blue fish");
Map<String, Integer> count = wordCount.count("one fish two fish red fish blue fish");
System.out.println(phrase);
System.out.println();
System.out.println(count);
}
When I run this program, the outputs that I have :
{ =7, =1}
{red=1, blue=1, one=1, fish=4, two=1}
I thought that the method splitAsStream would stream the matching elements in the regex as Stream. How can I correct that?
The problem seems to be that you are in fact splitting by words, i.e. you are streaming over everything that is not a word, or that is in between words. Unfortunately, there seems to be no equivalent method for streaming the actual match results (hard to believe, but I did not find any; feel free to comment if you know one).
Instead, you could just split by non-words, using \W instead of \w. Also, as noted in comments, you can make it a bit more readable by using String::toLowerCase instead of a lambda and Collectors.summingInt.
public static Map<String, Integer> countJava8(String input) {
return Pattern.compile("\\W+")
.splitAsStream(input)
.collect(Collectors.groupingBy(String::toLowerCase,
Collectors.summingInt(s -> 1)));
}
But IMHO this is still very hard to comprehend, not only because of the "inverse" lookup, and it's also difficult to generalize to other, more complex patterns. Personally, I would just go with the "old school" solution, maybe making it a bit more compact using the new getOrDefault.
public static Map<String, Integer> countOldschool(String input) {
Map<String, Integer> wordcount = new HashMap<>();
Matcher matcher = Pattern.compile("\\w+").matcher(input);
while (matcher.find()) {
String word = matcher.group().toLowerCase();
wordcount.put(word, wordcount.getOrDefault(word, 0) + 1);
}
return wordcount;
}
The result seems to be the same in both cases.
Try this.
String in = "go go go go og sd";
Map<String, Integer> map = new HashMap<String, Integer>();
//Replace all punctuation with space
String[] s = in.replaceAll("\\p{Punct}", " ").split("\\s+");
for(int i = 0; i < s.length; i++)
{
map.put(s[i], i);
}
Set<String> st = new HashSet<String>(map.keySet());
for(int k = 0; k < s.length; k++)
{
int i = 0;
Pattern p = Pattern.compile(s[k]);
Matcher m = p.matcher(in);
while (m.find()) {
i++;
}
map.put(s[k], i);
}
for(String strin : st)
{
System.out.println("String: " + strin.toString() + " - Occurrency: " + map.get(strin.toString()));
}
System.out.println("Word: " + s.length);
This is output
String: sd, Occurrency: 1
String: go, Occurrency: 4
String: og, Occurrency: 1
Word: 6

How to Split this String and store in HashMap

String str = "id1;;name1 || id2;;name2 || id3;;name3||";
into id1 name1 ...and then store it in hashmap as id1 - key , name1- value
id2 - key , name2 - value
......
One way to reach your goal is to use a StringTokenizer.
Code example:
public static void main(String[] args) {
String input = "id1;;name1 || id2;;name2 || id3;;name3||";
Map<String, String> map = new HashMap<>();
// You have to split two times
for (String outer : splitBy(input, " || ")) {
List<String> inner = splitBy(outer, ";;"); // for example: outer="id1;;name1"
// Make sure, you have two inner input-elements
if (inner.size() == 2) {
String key = inner.get(0); // First element of List = Key
String value = inner.get(1); // Second element of List = Value
map.put(key, value);
}
}
}
private static List<String> splitBy(String toSplit, String delimiter) {
List<String> tokens = new ArrayList<>();
StringTokenizer tokenizer = new StringTokenizer(toSplit, delimiter);
while (tokenizer.hasMoreTokens()) {
tokens.add(tokenizer.nextToken());
}
return tokens;
}
Also take a look at this: Scanner vs. StringTokenizer vs. String.Split
for this particular case you should do something like this:
Map<String, String> yourHashMap = new HashMap<String, String>();
String input = "id1;;name1 || id2;;name2 || id3;;name3||";
// "\" is special character so it need an escape
String[] yourStrings = input.split("\\|\\|");
String[] hashObject = new String[2];
for (int i = 0; i <= yourStrings.length - 1; i++) {
//fist you have to remove the whitespaces
yourStrings[i] = yourStrings[i].replaceAll("\\s+", "");
hashObject = yourStrings[i].split(";;");
yourHashMap.put(hashObject[0], hashObject[1]);
}
Your input string have a strange format, I recommend you to change it.

Categories