0

There is a HashMap I have which has keys and values inside. I want to replace keys with the values from the map in a string.

In the string, keys are written as this @keyName or @"keyName" these should be replaced with map.get("keyName")

Lets say our map is this

"key1" : "2"  
"key2" : "3"  
"key3" : "4"  
"key 4" : "5"
"key-5" : "6"

So if we process the string "hello world, I am @key1 years old.", it will become "hello world, I am 2 years old."

Instead of @key1, we could use @"key1". If we use it without quotes, a white space (space character) or EOF should follow the key name and the key name shouldn't have white space in it. But if the key name has a white space in it, then it should be in quotes.

And if we process the string "hello world, I am @"key@"key1"" years old.", at first step it should replace the special string inside the special string and become "hello world, I am @"key2" years old." and then with the second step it should be "hello world, I am 3 years old."

I have already done it for one special string, it doesn't recognize the special string within the special string. Here is the code:

private static Pattern specialStringPattern = Pattern.compile("@\"([^\"]*?)\"|@\\S+");

/** this replaces the keys inside a string with their values.
 * for example @keyName or @"keyName" is replaced with the value of the keyName. */
public static String specialStrings(String s) {
    Matcher matcher = specialStringPattern.matcher(s);
    while (matcher.find()) {
        String text = matcher.group();
        text = text.replace("@","").replaceAll("\"","");
        s = s.replace(matcher.group(),map.get(text));
    }
    return s;
}

Sorry for my English, and my lack of Regex knowledge. I think it should be easy to get the answer by modifying the code a little bit.

Here is some examples of what I need:

There is @key1 apples on the table.  
There is 2 apples on the table.

There is @"key1" apples on the table.  
There is 2 apples on the table.

There is @key 4 apples on the table.
There is null 4 apples on the table.

There is @"key 4" apples on the table.
There is 5 apples on the table.

There is @key@key2 apples on the table.
There is @key3 apples on the table. (second step)
There is 4 apples on the table. (final output)

There is @"key @"key3"" apples on the table.
There is @"key 4" apples on the table. (second step)
There is 5 apples on the table. (final output)

There is @"key @key3" apples on the table.
There is @"key 4" apples on the table. (second step)
There is 5 apples on the table. (final output)

There is @"key @key3 " apples on the table.
There is @"key 4 " apples on the table. (second step)
There is null apples on the table. (final output)

There is @key-5 apples on the table.
There is 6 apples on the table.
ossobuko
  • 851
  • 8
  • 25

2 Answers2

1

I made regex that matching your example here: https://regex101.com/r/nudYEl/2

@(\"[\w\s]+\")|(?!@(\w+)@(\w+))@(\w+)

and you just need to modify your function to recursive:

public static String specialStrings(String s) {
    Matcher matcher = specialStringPattern.matcher(s);
    boolean findAgain = false;
    while (matcher.find()) {
        String text = matcher.group();
        text = text.replace("@","").replaceAll("\"","");
        s = s.replace(matcher.group(),map.get(text));
        findAgain = true;
    }
    if (findAgain) return specialStrings(s);
    return s;
}

[Update]
regex: https://regex101.com/r/nudYEl/4

@(\"[\w\s-]+\")|(?!@([\w-]+)@([\w-]+))@([\w-]+)

Atmahadli
  • 687
  • 8
  • 14
  • There is a problem with the characters like '-'. The keys often use a dash between words. Like "key-1". Sorry I missed that. – ossobuko Nov 22 '16 at 18:47
  • Update to this: @(\"[^\"^@]+\")|(?!@[^\"^@^\s]+@)(@[^\"^@^\s]+) This way only @ and " couldn't be used in the key name. – ossobuko Nov 22 '16 at 21:34
  • cool! that worked too, I think you don't need to use `^` for every character inside `[...]` I try this work too `@(\"[^\"@]+\")|(?!@[^\"@\s]+@)(@[^\"@\s]+)` – Atmahadli Nov 23 '16 at 01:21
0

Don't use regex:

for (boolean hit = true; hit;) {
    hit = false;
    for (String key : map.keySet()) {
        if (str.contains("@\"" + key + "\"")) {
            str = str.replace("@\"" + key + "\"", map.get(key));
            hit = true;
        } else if (str.contains("@" + key  )) {
            str = str.replace("@" + key + "", map.get(key));
            hit = true;
        }
    }
}
Bohemian
  • 412,405
  • 93
  • 575
  • 722