MessageFormat.format() with named parameters

Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
5
down vote
favorite
I was looking for how to use MessageFormat.format() in Java with named parameters, as a similar option exists in Python, and found this question. Some functions are presented there, although they use internal cycles and StringBuilder, and apparently they can fall into infinite loops (comments there suggest that, and it makes sense).
Option 1 (potential infinite loop):
public static String format(String str, Map<String, Object> values)
StringBuilder builder = new StringBuilder(str);
for (Entry<String, Object> entry : values.entrySet())
int start;
String pattern = "%(" + entry.getKey() + ")";
String value = entry.getValue().toString();
// Replace every occurence of %(key) with value
while ((start = builder.indexOf(pattern)) != -1)
builder.replace(start, start + pattern.length(), value);
return builder.toString();
Option 2 (infinite loop removed):
public static String dictFormat(String format, Hashtable<String, Object> values)
StringBuilder convFormat = new StringBuilder(format);
Enumeration<String> keys = values.keys();
ArrayList valueList = new ArrayList();
int currentPos = 1;
while (keys.hasMoreElements())
String key = keys.nextElement(),
formatKey = "%(" + key + ")",
formatPos = "%" + Integer.toString(currentPos) + "$";
int index = -1;
while ((index = convFormat.indexOf(formatKey, index)) != -1)
convFormat.replace(index, index + formatKey.length(), formatPos);
index += formatPos.length();
valueList.add(values.get(key));
++currentPos;
return String.format(convFormat.toString(), valueList.toArray());
And the question is, why not something simpler? Why is there an internal cycle?
Here my option (which probably has some issue I'm not aware of).
public static String format(String str, Map<String, String> values) str.isEmpty())
return finalString;
// validate parameters
else if (values == null
java comparative-review formatting
add a comment |Â
up vote
5
down vote
favorite
I was looking for how to use MessageFormat.format() in Java with named parameters, as a similar option exists in Python, and found this question. Some functions are presented there, although they use internal cycles and StringBuilder, and apparently they can fall into infinite loops (comments there suggest that, and it makes sense).
Option 1 (potential infinite loop):
public static String format(String str, Map<String, Object> values)
StringBuilder builder = new StringBuilder(str);
for (Entry<String, Object> entry : values.entrySet())
int start;
String pattern = "%(" + entry.getKey() + ")";
String value = entry.getValue().toString();
// Replace every occurence of %(key) with value
while ((start = builder.indexOf(pattern)) != -1)
builder.replace(start, start + pattern.length(), value);
return builder.toString();
Option 2 (infinite loop removed):
public static String dictFormat(String format, Hashtable<String, Object> values)
StringBuilder convFormat = new StringBuilder(format);
Enumeration<String> keys = values.keys();
ArrayList valueList = new ArrayList();
int currentPos = 1;
while (keys.hasMoreElements())
String key = keys.nextElement(),
formatKey = "%(" + key + ")",
formatPos = "%" + Integer.toString(currentPos) + "$";
int index = -1;
while ((index = convFormat.indexOf(formatKey, index)) != -1)
convFormat.replace(index, index + formatKey.length(), formatPos);
index += formatPos.length();
valueList.add(values.get(key));
++currentPos;
return String.format(convFormat.toString(), valueList.toArray());
And the question is, why not something simpler? Why is there an internal cycle?
Here my option (which probably has some issue I'm not aware of).
public static String format(String str, Map<String, String> values) str.isEmpty())
return finalString;
// validate parameters
else if (values == null
java comparative-review formatting
add a comment |Â
up vote
5
down vote
favorite
up vote
5
down vote
favorite
I was looking for how to use MessageFormat.format() in Java with named parameters, as a similar option exists in Python, and found this question. Some functions are presented there, although they use internal cycles and StringBuilder, and apparently they can fall into infinite loops (comments there suggest that, and it makes sense).
Option 1 (potential infinite loop):
public static String format(String str, Map<String, Object> values)
StringBuilder builder = new StringBuilder(str);
for (Entry<String, Object> entry : values.entrySet())
int start;
String pattern = "%(" + entry.getKey() + ")";
String value = entry.getValue().toString();
// Replace every occurence of %(key) with value
while ((start = builder.indexOf(pattern)) != -1)
builder.replace(start, start + pattern.length(), value);
return builder.toString();
Option 2 (infinite loop removed):
public static String dictFormat(String format, Hashtable<String, Object> values)
StringBuilder convFormat = new StringBuilder(format);
Enumeration<String> keys = values.keys();
ArrayList valueList = new ArrayList();
int currentPos = 1;
while (keys.hasMoreElements())
String key = keys.nextElement(),
formatKey = "%(" + key + ")",
formatPos = "%" + Integer.toString(currentPos) + "$";
int index = -1;
while ((index = convFormat.indexOf(formatKey, index)) != -1)
convFormat.replace(index, index + formatKey.length(), formatPos);
index += formatPos.length();
valueList.add(values.get(key));
++currentPos;
return String.format(convFormat.toString(), valueList.toArray());
And the question is, why not something simpler? Why is there an internal cycle?
Here my option (which probably has some issue I'm not aware of).
public static String format(String str, Map<String, String> values) str.isEmpty())
return finalString;
// validate parameters
else if (values == null
java comparative-review formatting
I was looking for how to use MessageFormat.format() in Java with named parameters, as a similar option exists in Python, and found this question. Some functions are presented there, although they use internal cycles and StringBuilder, and apparently they can fall into infinite loops (comments there suggest that, and it makes sense).
Option 1 (potential infinite loop):
public static String format(String str, Map<String, Object> values)
StringBuilder builder = new StringBuilder(str);
for (Entry<String, Object> entry : values.entrySet())
int start;
String pattern = "%(" + entry.getKey() + ")";
String value = entry.getValue().toString();
// Replace every occurence of %(key) with value
while ((start = builder.indexOf(pattern)) != -1)
builder.replace(start, start + pattern.length(), value);
return builder.toString();
Option 2 (infinite loop removed):
public static String dictFormat(String format, Hashtable<String, Object> values)
StringBuilder convFormat = new StringBuilder(format);
Enumeration<String> keys = values.keys();
ArrayList valueList = new ArrayList();
int currentPos = 1;
while (keys.hasMoreElements())
String key = keys.nextElement(),
formatKey = "%(" + key + ")",
formatPos = "%" + Integer.toString(currentPos) + "$";
int index = -1;
while ((index = convFormat.indexOf(formatKey, index)) != -1)
convFormat.replace(index, index + formatKey.length(), formatPos);
index += formatPos.length();
valueList.add(values.get(key));
++currentPos;
return String.format(convFormat.toString(), valueList.toArray());
And the question is, why not something simpler? Why is there an internal cycle?
Here my option (which probably has some issue I'm not aware of).
public static String format(String str, Map<String, String> values) str.isEmpty())
return finalString;
// validate parameters
else if (values == null
java comparative-review formatting
edited May 15 at 15:39
Sam Onela
5,76961543
5,76961543
asked May 15 at 11:05
Fernando César S.
262
262
add a comment |Â
add a comment |Â
1 Answer
1
active
oldest
votes
up vote
2
down vote
Performing string substitutions using multiple passes is almost always the wrong approach, and leads to bugs. If one of the values happens to be a string that looks like a %(key), then all sorts of unpredictable things could happen, including various uncontrolled format string attacks!
Therefore, the string replacements must be done in a single pass of the format string. I recommend doing it using a regular expression.
Furthermore, your method provides no escape mechanism, in case you need to specify a literal %(blah) in the format string. In Java, it would be customary to use backslash as an escape character.
Suggested solution
This solution uses Matcher.replaceAll(Function<MatchResult,String> replacer), which was introduced in Java 9, to provide each substitution text via a callback.
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class NamedFormatter
private static final Pattern RE = Pattern.compile(
"\\(.)" + // Treat any character after a backslash literally
"
add a comment |Â
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
2
down vote
Performing string substitutions using multiple passes is almost always the wrong approach, and leads to bugs. If one of the values happens to be a string that looks like a %(key), then all sorts of unpredictable things could happen, including various uncontrolled format string attacks!
Therefore, the string replacements must be done in a single pass of the format string. I recommend doing it using a regular expression.
Furthermore, your method provides no escape mechanism, in case you need to specify a literal %(blah) in the format string. In Java, it would be customary to use backslash as an escape character.
Suggested solution
This solution uses Matcher.replaceAll(Function<MatchResult,String> replacer), which was introduced in Java 9, to provide each substitution text via a callback.
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class NamedFormatter
private static final Pattern RE = Pattern.compile(
"\\(.)" + // Treat any character after a backslash literally
"
add a comment |Â
up vote
2
down vote
Performing string substitutions using multiple passes is almost always the wrong approach, and leads to bugs. If one of the values happens to be a string that looks like a %(key), then all sorts of unpredictable things could happen, including various uncontrolled format string attacks!
Therefore, the string replacements must be done in a single pass of the format string. I recommend doing it using a regular expression.
Furthermore, your method provides no escape mechanism, in case you need to specify a literal %(blah) in the format string. In Java, it would be customary to use backslash as an escape character.
Suggested solution
This solution uses Matcher.replaceAll(Function<MatchResult,String> replacer), which was introduced in Java 9, to provide each substitution text via a callback.
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class NamedFormatter
private static final Pattern RE = Pattern.compile(
"\\(.)" + // Treat any character after a backslash literally
"
add a comment |Â
up vote
2
down vote
up vote
2
down vote
Performing string substitutions using multiple passes is almost always the wrong approach, and leads to bugs. If one of the values happens to be a string that looks like a %(key), then all sorts of unpredictable things could happen, including various uncontrolled format string attacks!
Therefore, the string replacements must be done in a single pass of the format string. I recommend doing it using a regular expression.
Furthermore, your method provides no escape mechanism, in case you need to specify a literal %(blah) in the format string. In Java, it would be customary to use backslash as an escape character.
Suggested solution
This solution uses Matcher.replaceAll(Function<MatchResult,String> replacer), which was introduced in Java 9, to provide each substitution text via a callback.
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class NamedFormatter
private static final Pattern RE = Pattern.compile(
"\\(.)" + // Treat any character after a backslash literally
"
Performing string substitutions using multiple passes is almost always the wrong approach, and leads to bugs. If one of the values happens to be a string that looks like a %(key), then all sorts of unpredictable things could happen, including various uncontrolled format string attacks!
Therefore, the string replacements must be done in a single pass of the format string. I recommend doing it using a regular expression.
Furthermore, your method provides no escape mechanism, in case you need to specify a literal %(blah) in the format string. In Java, it would be customary to use backslash as an escape character.
Suggested solution
This solution uses Matcher.replaceAll(Function<MatchResult,String> replacer), which was introduced in Java 9, to provide each substitution text via a callback.
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class NamedFormatter
private static final Pattern RE = Pattern.compile(
"\\(.)" + // Treat any character after a backslash literally
"
edited May 15 at 14:15
answered May 15 at 13:24
200_success
123k14143399
123k14143399
add a comment |Â
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f194446%2fmessageformat-format-with-named-parameters%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password