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.
2
  • Is the solution acceptable for you? stackoverflow.com/a/3655963/2027465 Commented Nov 22, 2016 at 14:46
  • @VitaliyPro I don't think it is applicable. I thought I explained the rules clearly. Thanks. Commented Nov 22, 2016 at 15:56

2 Answers 2

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-]+)

Sign up to request clarification or add additional context in comments.

3 Comments

There is a problem with the characters like '-'. The keys often use a dash between words. Like "key-1". Sorry I missed that.
Update to this: @(\"[^\"^@]+\")|(?!@[^\"^@^\s]+@)(@[^\"^@^\s]+) This way only @ and " couldn't be used in the key name.
cool! that worked too, I think you don't need to use ^ for every character inside [...] I try this work too @(\"[^\"@]+\")|(?!@[^\"@\s]+@)(@[^\"@\s]+)
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;
        }
    }
}

3 Comments

This doesn't recognize the inner special String. The first quote of the inner special string finishes the special string.
@ossobuko you're right. I edited my answer to something different that works (tested too!)
Oh no! You are going through thousands of keys. This is a frequently used method.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.