0

I have the following scenario in my current Java project:

A properties file:

animal1=cat
animal2=dog

A Java method:

public String replace(String input) {
  return input.replaceAll("%(.*?)%", properties.getProperty("$1"));
}

The part that says properties.getProperty("$1") obviously doesn't work because it will return the property for the key "$1" but not for the actual value for $1.

Is there any simple method to replace for example "%animal1%" with "cat"?

The properties file will contain a few hundred entries, so searching after a substring that could be replaced for every value in the properties file is not an option.

2 Answers 2

1

Don't try to do it as oneliner. If you use a loop to check for all the patterns that might match

Here's some code that will do the trick for you (this should compile and run as-is)

package org.test.stackoverflow;

import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class PatternReplacer {
  private final Pattern keyPattern = Pattern.compile("%([^%]*)%");
  private final Properties properties;

  public PatternReplacer(Properties propertySeed) {
    properties = propertySeed;
  }

  public String replace(String input) {
    int start = 0;

    while(true) {
      Matcher match = keyPattern.matcher(input);

      if(!match.find(start)) break;

      String group = match.group(1);
      if(properties.containsKey(group)) {
        input = input.replaceAll("%" + group + "%", properties.getProperty(group));
      } else {
        start = match.start() + group.length();
      }
    }

    return input;
  }

  public static void main(String... args) {
    Properties p = new Properties();
    p.put("animal1", "cat");
    p.put("animal2", "dog");

    PatternReplacer test = new PatternReplacer(p);
    String result = test.replace("foo %animal1% %bar% %animal2%baz %animal1% qu%ux");
    System.out.println(result);
  }
}

Output:

foo cat %bar% dogbaz cat qu%ux
Sign up to request clarification or add additional context in comments.

1 Comment

I improved the regex based on the answer by @Pshemo (thank you), take note of the edit
1

If I understand you correctly you will need to use manually use appendReplacement and appendTail methods from Matcher class. This will allow you to pass result of properties.getProperty(matcher.group(1))

Here is basic example of how you can use it. In this example I'm searching for some keyword like string or secret to replace them. Replacement is decided dynamically based on mapping like

  • string->foo,
  • secret->whatever

and is determined by simply calling get(keyword) from Map which stores this mapping.

String data = "some string with some secret data";

Map<String,String> properties = new HashMap<>();
properties.put("string", "foo");
properties.put("secret", "whatever");

Pattern p = Pattern.compile("string|secret");
Matcher m = p.matcher(data);

StringBuffer sb = new StringBuffer();
while (m.find()){
    m.appendReplacement(sb, properties.get(m.group()));//replace found match 
                                                //with result based on group
}
m.appendTail(sb);//append rest of text after last match, in our case " data"

String result = sb.toString();
System.out.println("Original: " + data);
System.out.println("Replaced: " + result);

Result:

Original: some string with some secret data
Replaced: some foo with some whatever data

8 Comments

He wants the extra strings to be bounded by %secret% or whatever, your code doesn't handle the % characters. It also doesn't the regex pattern from the Properties object.
@durron597 My answer is just a example which can be used to create proper code. OP already has correct regex which will find properties - strings between % ("%(.*?)%" - which can be improved to "%([^%]*)%" to avoid unnecessary backtracking) so I didn't add it to my answer. Also Map is quite similar to Properties so I don't see problem here. Again, my answer is not the solution, but guide of how to create one.
The problem here is that I have to compile the pattern for each possible key in properties. With hundreds of items in the properties map, this would be very slow.
@mtronics I am not sure what is the problem here. Properties class extends Hashtable which means that searching value for key should be very fast (values are stored in buckets based on hashcode() of used key, so most of incorrect ones are fildered right away). Only problem I see is that Hashtable has thread safe mechanism so it takes some time to get lock/monitor of Hashmap, but to solve it you can first copy content of your Properties to some Map like HashMap which doesn't have this problem and use it instead of Properties.
@mtronics Based on code example from your question your properties are surrounded by % so your regex %(.?*)% should work fine here. What do you mean by "The problem here is that I have to compile the pattern for each possible key in properties"?
|

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.