【发布时间】:2014-03-13 15:55:41
【问题描述】:
我有来自脚本的数据行,通常看起来像这样(单行示例):
1234567890;group1;varname1;133333337;prop1=val1;prop2=val2;prop3=val3
我需要将每一行分解为 Map 的键值项,每个项由分隔符字符串分隔(示例中为 ;,但也可以是自定义项)。前 4 项是静态的,这意味着只有值在行中,并且键是已知的。其余的是可变数量的键值项(0 个或多个 key=value 块)。 请先看看下面的输出给你一个想法。
我已经有两种工作方法来实现这一点,它们都为同一行提供相同的输出。出于好奇,我已经建立了一个测试类来演示这两种方法以及一些(简单的)性能分析。 请注意在下面显示的方法中,无效输入处理最少。
字符串拆分(使用 Apache Commons):
private static List<String> splitParsing(String dataLine, String separator) {
List<String> output = new ArrayList<String>();
long begin = System.nanoTime();
String[] data = StringUtils.split(dataLine, separator);
if (data.length >= STATIC_PROPERTIES.length) {
// Static properties (always there).
for (int i = 0; i < STATIC_PROPERTIES.length; i++) {
output.add(STATIC_PROPERTIES[i] + " = " + data[i]);
}
// Dynamic properties (0 or more).
for (int i = STATIC_PROPERTIES.length; i < data.length; i++) {
String[] fragments = StringUtils.split(data[i], KEYVALUE_SEPARATOR);
if (fragments.length == 2) {
output.add(fragments[0] + " = " + fragments[1]);
}
}
}
long end = System.nanoTime();
output.add("Execution time: " + (end - begin) + "ns");
return output;
}
正则表达式(使用 JDK 1.6):
private static List<String> regexParsing(String dataLine, String separator) {
List<String> output = new ArrayList<String>();
long begin = System.nanoTime();
Pattern linePattern = Pattern.compile(StringUtils.replace(DATA_PATTERN_TEMPLATE, SEP, separator));
Pattern propertiesPattern = Pattern.compile(StringUtils.replace(PROPERTIES_PATTERN_TEMPLATE, SEP, separator));
Matcher lineMatcher = linePattern.matcher(dataLine);
if (lineMatcher.matches()) {
// Static properties (always there).
for (int i = 0; i < STATIC_PROPERTIES.length; i++) {
output.add(STATIC_PROPERTIES[i] + " = " + lineMatcher.group(i + 1));
}
Matcher propertiesMatcher = propertiesPattern.matcher(lineMatcher.group(STATIC_PROPERTIES.length + 1));
while (propertiesMatcher.find()) {
output.add(propertiesMatcher.group(1) + " = " + propertiesMatcher.group(2));
}
}
long end = System.nanoTime();
output.add("Execution time: " + (end - begin) + "ns");
return output;
}
主要方法:
public static void main(String[] args) {
String input = "1234567890;group1;varname1;133333337;prop1=val1;prop2=val2;prop3=val3";
System.out.println("Split parsing:");
for (String line : splitParsing(input, ";")) {
System.out.println(line);
}
System.out.println();
System.out.println("Regex parsing:");
for (String line : regexParsing(input, ";")) {
System.out.println(line);
}
}
常量:
// Common constants.
private static final String TIMESTAMP_KEY = "TMST";
private static final String GROUP_KEY = "GROUP";
private static final String VARIABLE_KEY = "VARIABLE";
private static final String VALUE_KEY = "VALUE";
private static final String KEYVALUE_SEPARATOR = "=";
private static final String[] STATIC_PROPERTIES = { TIMESTAMP_KEY, GROUP_KEY, VARIABLE_KEY, VALUE_KEY };
// Regex constants.
private static final String SEP = "{sep}";
private static final String PROPERTIES_PATTERN_TEMPLATE = SEP + "(\\w+)" + KEYVALUE_SEPARATOR + "(\\w+)";
private static final String DATA_PATTERN_TEMPLATE = "(\\d+)" + SEP + "(\\w+)" + SEP + "(\\w+)" + SEP + "(\\d+\\.?\\d*)"
+ "((?:" + PROPERTIES_PATTERN_TEMPLATE + ")*)";
主要方法的输出:
Split parsing:
TMST = 1234567890
GROUP = group1
VARIABLE = varname1
VALUE = 133333337
prop1 = val1
prop2 = val2
prop3 = val3
Execution time: 8695796ns
Regex parsing:
TMST = 1234567890
GROUP = group1
VARIABLE = varname1
VALUE = 133333337
prop1 = val1
prop2 = val2
prop3 = val3
Execution time: 1250787ns
从输出(我运行了多次)来看,似乎正则表达式方法在性能方面更有效,尽管我最初的想法更倾向于拆分方法。但是,我不确定这种性能分析的代表性。
我的问题是:
- 对于无效输入处理,这两种方法中哪一种最适合或更容易使用? (例如:静态项目丢失、格式无效等)。
- 哪些方法不太可能产生意外行为?
- 为什么正则表达式方法更快?我会假设相反,因为
Matchers 和Patterns 背后肯定有更复杂的逻辑。我的绩效分析是否具有代表性?
【问题讨论】:
-
鉴于
System.out.println的电话,我会担心报告的持续时间的有效性。将文本收集到某种字符串生成器中并在end = System.nanoTime();之后打印可能会更好。 -
确实!原始上下文中的代码将解析的项目添加到
List,我将使用该行为调整上面的代码。 -
@AdrianHHH 我根据您的建议编辑了问题。
标签: java regex performance parsing split