Question

My requirement is that I have a given string like String originalString = "delhi to goa";

And I have a string String regStr = "%{orgCity} to %{destCity}";

The given text can be in any format. (Not just "delhi to goa", it can be "delhi goa to")

Now, given these two strings, I want to get a HashMap with key value pair as

orgCity -> delhi

destCity -> goa

Here key is the string between %{ and } . And value is the corresponding string in the originalString.

This needs to be implemented using some regex / pattern.

I could not find the solution for this.

Can someone help on this??

Thanks

Updated

Solution:

public static void main(String[] args) {

    // Original requirement
    System.out.println(getValueMap("%{orgCity} to %{destCity}", "delhi to goa"));

    // A variation with two words values
    System.out.println(getValueMap("%{orgCity} to %{destCity}", "New York to Mexico"));

    // Another variation
    System.out.println(getValueMap("%{orgCity} to %{destCity} and more", "delhi to goa and more"));

    // order of words doesn't matter
    System.out.println(getValueMap("%{orgCity} %{destCity} to", "delhi goa to"));

    // different strings than the original requirement
    System.out.println(getValueMap("I'm going to %{firstCity} and then to %{secondCity}", "I'm going to Nauru and then to Seattle"));

    // more than two values, with more than one word
    System.out.println(getValueMap("I am %{age} years old, I have %{eyesColour} eyes and %{pocketContent} in my pocket",
              "I am 20 years old, I have dark blue eyes and two coins in my pocket"));

    // etc ...
}

public static Map<String, String> getValueMap(String format, String text) {
    Map<String, String> map = new HashMap<String, String>();
    String pattern = format;
    String[] keyList = StringUtils.substringsBetween(format, "%{", "}");
    for (String str : keyList) {
        pattern = pattern.replaceAll("\\%\\{" + str + "\\}", ("(.+)"));
    }
    Pattern r = Pattern.compile(pattern);

    Matcher m = r.matcher(text);
    if(!m.find()) {
        throw new RuntimeException("regStr and originalString don't match");
    }
    for (int i = 0; i < m.groupCount(); i++) {
        map.put(keyList[i], m.group(i+1));
    }
    return map;
}
Was it helpful?

Solution

I know I shouldn't do your work for you, but that exercise you propose was so interesting to me that I just couldn't resist:

This method receives your two strings and gives you back a Map (ok, just change the return type if you REALLY want a HashMap instead):

public static Map<String, String> getMap(String regStr, String originalString) {

    Pattern searchPattern = Pattern.compile("%\\{([^}]+)\\}");
    Matcher matcher = searchPattern.matcher(regStr);
    StringBuilder builder = new StringBuilder();
    List<String> keys = new LinkedList<>();
    Map<String, String> map = new HashMap<>();

    int start = 0;

    while(matcher.find()) {
        builder.append(Pattern.quote(regStr.substring(start, matcher.start())))
                .append("(.+)");
        start = matcher.end();
        keys.add(matcher.group(1));
    }
    builder.append(Pattern.quote(regStr.substring(start)));

    Pattern finalPattern = Pattern.compile(builder.toString());

    matcher = finalPattern.matcher(originalString);
    int pos = 0;
    if(!matcher.find()) {
        throw new RuntimeException("regStr and originalString don't match");
    }
    for(String key: keys) {
        map.put(key, matcher.group(++pos));
    }
    return map;
}

Some light testing:

public static void main(String[] args) {

    // Original requirement
    System.out.println(getMap("%{orgCity} to %{destCity}", "delhi to goa"));

    // A variation with two words values
    System.out.println(getMap("%{orgCity} to %{destCity}", "New York to Mexico"));

    // Another variation
    System.out.println(getMap("%{orgCity} to %{destCity} and more", "delhi to goa and more"));

    // order of words doesn't matter
    System.out.println(getMap("%{orgCity} %{destCity} to", "delhi goa to"));

    // different strings than the original requirement
    System.out.println(getMap("I'm going to %{firstCity} and then to %{secondCity}", "I'm going to Nauru and then to Seattle"));

    // more than two values, with more than one word
    System.out.println(getMap("I am %{age} years old, I have %{eyesColour} eyes and %{pocketContent} in my pocket",
              "I am 20 years old, I have dark blue eyes and two coins in my pocket"));

    // etc ...
}

OTHER TIPS

Time to practice your regex skills http://www.regexr.com/

Create two capture groups and regex each string.

If it is always going to be in the format: someCity to someCity you can use the String.split method.

String input = "delhi to goa";
String[] arr = input.split(" to ");
Map<String, String> map = new HashMap<>();
map.put(arr[0], arr[1]);

You can use regex (\w+)\sto\s(\w+) and can find two groups. Group 1 for key and Group 2 for value.

You can test this regular expression on http://rubular.com/

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top