获取 Formatter.format() 字符串中占位符的数量
Get number of placeholders in Formatter.format() String
在一个 Java 程序中,我使用了一个带有 Formatter.format()
函数的字符串,它是我从服务器获取的。我无法确定要格式化的 String
是否具有占位符或占位符的有效数量。如果 String
与预期不符,我想抛出异常 - 或者以某种方式记录它。
此时我不关心占位符是什么类型(String
,Integer
,...),我只想获取每个字符串的预期参数数量.
实现此目的最简单的方法是什么?一种方法是使用正则表达式,但我在想是否有更方便的方法 - 例如内置函数。
这里有一些例子:
Example String | number of placeholders:
%d of %d | 2
This is my %s | 1
A simple content. | 0
This is 100% | 0
Hi! My name is %s and I have %d dogs and a %d cats. | 3
编辑:
如果提供的参数不足,Formatter.format() 将抛出异常。我有可能得到一个没有占位符的字符串。在这种情况下,即使我提供了参数(将被省略),也不会抛出任何异常(尽管我想抛出一个),只会返回该字符串值。我需要向服务器报告错误。
您可以使用定义占位符格式的正则表达式来计算字符串中的匹配总数。
// %[argument_index$][flags][width][.precision][t]conversion
String formatSpecifier
= "%(\d+\$)?([-#+ 0,(\<]*)?(\d+)?(\.\d+)?([tT])?([a-zA-Z%])";
// The pattern that defines a placeholder
Pattern pattern = Pattern.compile(formatSpecifier);
// The String to test
String[] values = {
"%d of %d",
"This is my %s",
"A simple content.",
"This is 100%", "Hi! My name is %s and I have %d dogs and a %d cats."
};
// Iterate over the Strings to test
for (String value : values) {
// Build the matcher for a given String
Matcher matcher = pattern.matcher(value);
// Count the total amount of matches in the String
int counter = 0;
while (matcher.find()) {
counter++;
}
// Print the result
System.out.printf("%s=%d%n", value, counter);
}
输出:
%d of %d=2
This is my %s=1
A simple content.=0
This is 100%=0
Hi! My name is %s and I have %d dogs and a %d cats.=3
我已经适配了String.format()
的代码。这是结果:
private static final String formatSpecifier
= "%(\d+\$)?([-#+ 0,(\<]*)?(\d+)?(\.\d+)?([tT])?([a-zA-Z%])";
private static Pattern fsPattern = Pattern.compile(formatSpecifier);
private static int parse(String s) {
int count = 0;
Matcher m = fsPattern.matcher(s);
for (int i = 0, len = s.length(); i < len; ) {
if (m.find(i)) {
// Anything between the start of the string and the beginning
// of the format specifier is either fixed text or contains
// an invalid format string.
if (m.start() != i) {
// Make sure we didn't miss any invalid format specifiers
checkText(s, i, m.start());
// Assume previous characters were fixed text
}
count++;
i = m.end();
} else {
// No more valid format specifiers. Check for possible invalid
// format specifiers.
checkText(s, i, len);
// The rest of the string is fixed text
break;
}
}
return count;
}
private static void checkText(String s, int start, int end) {
for (int i = start; i < end; i++) {
// Any '%' found in the region starts an invalid format specifier.
if (s.charAt(i) == '%') {
char c = (i == end - 1) ? '%' : s.charAt(i + 1);
throw new UnknownFormatConversionException(String.valueOf(c));
}
}
}
测试:
public static void main(String[] args) {
System.out.println(parse("Hello %s, My name is %s. I am %d years old."));
}
输出:
3
在一个 Java 程序中,我使用了一个带有 Formatter.format()
函数的字符串,它是我从服务器获取的。我无法确定要格式化的 String
是否具有占位符或占位符的有效数量。如果 String
与预期不符,我想抛出异常 - 或者以某种方式记录它。
此时我不关心占位符是什么类型(String
,Integer
,...),我只想获取每个字符串的预期参数数量.
实现此目的最简单的方法是什么?一种方法是使用正则表达式,但我在想是否有更方便的方法 - 例如内置函数。
这里有一些例子:
Example String | number of placeholders:
%d of %d | 2
This is my %s | 1
A simple content. | 0
This is 100% | 0
Hi! My name is %s and I have %d dogs and a %d cats. | 3
编辑: 如果提供的参数不足,Formatter.format() 将抛出异常。我有可能得到一个没有占位符的字符串。在这种情况下,即使我提供了参数(将被省略),也不会抛出任何异常(尽管我想抛出一个),只会返回该字符串值。我需要向服务器报告错误。
您可以使用定义占位符格式的正则表达式来计算字符串中的匹配总数。
// %[argument_index$][flags][width][.precision][t]conversion
String formatSpecifier
= "%(\d+\$)?([-#+ 0,(\<]*)?(\d+)?(\.\d+)?([tT])?([a-zA-Z%])";
// The pattern that defines a placeholder
Pattern pattern = Pattern.compile(formatSpecifier);
// The String to test
String[] values = {
"%d of %d",
"This is my %s",
"A simple content.",
"This is 100%", "Hi! My name is %s and I have %d dogs and a %d cats."
};
// Iterate over the Strings to test
for (String value : values) {
// Build the matcher for a given String
Matcher matcher = pattern.matcher(value);
// Count the total amount of matches in the String
int counter = 0;
while (matcher.find()) {
counter++;
}
// Print the result
System.out.printf("%s=%d%n", value, counter);
}
输出:
%d of %d=2
This is my %s=1
A simple content.=0
This is 100%=0
Hi! My name is %s and I have %d dogs and a %d cats.=3
我已经适配了String.format()
的代码。这是结果:
private static final String formatSpecifier
= "%(\d+\$)?([-#+ 0,(\<]*)?(\d+)?(\.\d+)?([tT])?([a-zA-Z%])";
private static Pattern fsPattern = Pattern.compile(formatSpecifier);
private static int parse(String s) {
int count = 0;
Matcher m = fsPattern.matcher(s);
for (int i = 0, len = s.length(); i < len; ) {
if (m.find(i)) {
// Anything between the start of the string and the beginning
// of the format specifier is either fixed text or contains
// an invalid format string.
if (m.start() != i) {
// Make sure we didn't miss any invalid format specifiers
checkText(s, i, m.start());
// Assume previous characters were fixed text
}
count++;
i = m.end();
} else {
// No more valid format specifiers. Check for possible invalid
// format specifiers.
checkText(s, i, len);
// The rest of the string is fixed text
break;
}
}
return count;
}
private static void checkText(String s, int start, int end) {
for (int i = start; i < end; i++) {
// Any '%' found in the region starts an invalid format specifier.
if (s.charAt(i) == '%') {
char c = (i == end - 1) ? '%' : s.charAt(i + 1);
throw new UnknownFormatConversionException(String.valueOf(c));
}
}
}
测试:
public static void main(String[] args) {
System.out.println(parse("Hello %s, My name is %s. I am %d years old."));
}
输出:
3