Reputation: 56904
I will be given Strings that contain formatted "properties"; that is, Strings encapsulated inside the standard "${" and "}" tokens:
"This is an ${example} of a ${string} that I may be ${given}."
I will also have a HashMap<String,String>
containing substitutions for each possible formatted property:
HashMap Keys HashMapValues
===========================================
bacon eggs
ham salads
So that, given the following String:
"I like to eat ${bacon} and ${ham}."
I can send this to a Java method that will transform it into:
"I like to eat eggs and salads."
Here's my best attempt:
System.out.println("Starting...");
String regex = "$\\{*\\}";
Map<String,String> map = new HashMap<String, String>();
map.put("bacon", "eggs");
map.put("ham", "salads");
String sampleString = "I like ${bacon} and ${ham}.";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(sampleString);
while(matcher.find()) {
System.out.println("Found " + matcher.group());
// Strip leading "${" and trailing "}" off.
String property = matcher.group();
if(property.startsWith("${"))
property = property.substring(2);
if(property.endsWith("}"))
property = property.substring(0, property.length() - 1);
System.out.println("Before being replaced, property is: " + property);
if(map.containsKey(property))
property = map.get(property);
// Now, not sure how to locate the original property ("${bacon}", etc.)
// inside the sampleString so that I can replace "${bacon}" with
// "eggs".
}
System.out.println("Ending...");
When I execute this, I get no errors, but just see the "Starting..." and "Ending..." outputs. This tells me that my regex is incorrect, and so the Matcher
isn't able to match any properties.
So my first question is: what should this regex be?
Once I'm past that, I'm not sure how to perform the string replace once I've changed "${bacon}" into "eggs", etc. Any ideas? Thanks in advance!
Upvotes: 6
Views: 8810
Reputation: 41
Better use StrSubstitutor from apache commons lang. It can also substitute System props.
Since commons-lang 3.6 StrSubstitutor has been deprecated in favour of commons-text StringSubstitutor. Example:
import org.apache.commons.text.StringSubstitutor;
Properties props = new Properties();
props.setProperty("bacon", "eggs");
props.setProperty("ham", "salads");
String sampleString = "I like ${bacon} and ${ham}.";
String replaced = StringSubstitutor.replace(sampleString, props);
Upvotes: 4
Reputation: 89557
Use this instead:
String regex = "\\$\\{([^}]*)\\}";
Then you obtain only the content between ${
and }
that is inside the capture group 1.
Note that the $
has a special meaning in a pattern: end of the string
Thus it musts be escaped to be seen as literal (as curly brackets).
Upvotes: 4
Reputation: 3048
For completion, here is a working solution:
static final Pattern EXPRESSION_PATTERN = Pattern.compile("\\$\\{([^}]*)\\}");
/**
* Replace ${properties} in an expression
* @param expression expression string
* @param properties property map
* @return resolved expression string
*/
static String resolveExpression(String expression, Map<String, String> properties) {
StringBuilder result = new StringBuilder(expression.length());
int i = 0;
Matcher matcher = EXPRESSION_PATTERN.matcher(expression);
while(matcher.find()) {
// Strip leading "${" and trailing "}" off.
result.append(expression.substring(i, matcher.start()));
String property = matcher.group();
property = property.substring(2, property.length() - 1);
if(properties.containsKey(property)) {
//look up property and replace
property = properties.get(property);
} else {
//property not found, don't replace
property = matcher.group();
}
result.append(property);
i = matcher.end();
}
result.append(expression.substring(i));
return result.toString();
}
Upvotes: 2
Reputation: 1573
Why don't use a .properties file?, that way you could get all your messages from that file and could be separate from your code, something like (file example.properties):
message1=This is a {0} with format markers on it {1}
And then in your class load your bundle and use it like this:
ResourceBundle bundle = ResourceBundle.getBundle("example.properties", Locale.getDefault());
MessageFormat.format(bundle.getString('message1'), "param0", "param1"); // This gonna be your formatted String "This is a param0 with format markers on it param1"
You could use the MessageFormat (is a java.util library) without the bundle (just use the String directly), but again, having a bundle makes your code clear (and gives easy internationalization)
Upvotes: 6