为什么Java中的大多数字符串操作都基于regexp?
在Java中,有许多方法都与操作字符串有关。 最简单的例子是String.split(“something”)方法 现在,这些方法的实际定义是,它们都以正则表达式作为输入参数。这使得所有的构建块都非常强大 现在,您将在许多方法中看到两种效果:为什么Java中的大多数字符串操作都基于regexp?,java,regex,string,language-design,Java,Regex,String,Language Design,在Java中,有许多方法都与操作字符串有关。 最简单的例子是String.split(“something”)方法 现在,这些方法的实际定义是,它们都以正则表达式作为输入参数。这使得所有的构建块都非常强大 现在,您将在许多方法中看到两种效果: 每次调用该方法时,它们都会重新编译表达式。因此,它们会对性能产生影响 我发现在大多数“现实生活”的情况下,这些方法被称为“固定”文本。split方法最常见的用法甚至更糟:它通常是用单个字符(通常是一个“”、一个“;”或一个“&”)来调用的 因此,这不仅是因
最新消息:我打了几个电话,看看各种拆分字符串的方法需要多长时间 简短总结:它产生了巨大的差异 我为每个测试用例进行了10000000次迭代,始终使用输入
"aap,noot,mies,wim,zus,jet,teun"
并始终使用“,”或“,”作为拆分参数
这是我在Linux系统上得到的(它是Atom D510盒,所以有点慢):
正如您所看到的,如果您有很多“固定字符”拆分要做,那么它会产生很大的不同
给你们一些见解;我目前在ApacheLogFiles和Hadoop竞技场,拥有一个大型网站的数据。所以对我来说,这些东西真的很重要:)
这里我没有考虑垃圾收集器。据我所知,将正则表达式编译成Pattern/Matcher/。。将分配大量需要收集的对象。因此,从长远来看,这些版本之间的差异可能更大。。。。或更小
到目前为止,我的结论是:
- 只有在有很多字符串需要拆分时才对其进行优化
- 如果您使用regex方法,那么如果您重复使用相同的模式,则始终可以预编译
- 忘记(过时的)StringTokenizer
- 如果您想在单个字符上拆分,那么请使用自定义方法,特别是如果您只需要将其拆分为特定数量的片段(如…2)
private static String[]
stringSplitChar(final String input,
final char separator) {
int pieces = 0;
// First we count how many pieces we will need to store ( = separators + 1 )
int position = 0;
do {
pieces++;
position = input.indexOf(separator, position + 1);
} while (position != -1);
// Then we allocate memory
final String[] result = new String[pieces];
// And start cutting and copying the pieces.
int previousposition = 0;
int currentposition = input.indexOf(separator);
int piece = 0;
final int lastpiece = pieces - 1;
while (piece < lastpiece) {
result[piece++] = input.substring(previousposition, currentposition);
previousposition = currentposition + 1;
currentposition = input.indexOf(separator, previousposition);
}
result[piece] = input.substring(previousposition);
return result;
}
private static String[]
stringSplitChar(final String input,
final char separator,
final int maxpieces) {
if (maxpieces <= 0) {
return stringSplitChar(input, separator);
}
int pieces = maxpieces;
// Then we allocate memory
final String[] result = new String[pieces];
// And start cutting and copying the pieces.
int previousposition = 0;
int currentposition = input.indexOf(separator);
int piece = 0;
final int lastpiece = pieces - 1;
while (currentposition != -1 && piece < lastpiece) {
result[piece++] = input.substring(previousposition, currentposition);
previousposition = currentposition + 1;
currentposition = input.indexOf(separator, previousposition);
}
result[piece] = input.substring(previousposition);
// All remaining array elements are uninitialized and assumed to be null
return result;
}
private static String[]
stringChop(final String input,
final char separator) {
String[] result;
// Find the separator.
final int separatorIndex = input.indexOf(separator);
if (separatorIndex == -1) {
result = new String[1];
result[0] = input;
}
else {
result = new String[2];
result[0] = input.substring(0, separatorIndex);
result[1] = input.substring(separatorIndex + 1);
}
return result;
}
私有静态字符串[]
stringSplitChar(最终字符串输入,
最终炭分离器){
整数=0;
//首先,我们计算需要存储多少件(=分离器+1)
int位置=0;
做{
工件++;
位置=input.indexOf(分隔符,位置+1);
}而(位置!=-1);
//然后我们分配内存
最终字符串[]结果=新字符串[片段];
//然后开始切割和复制碎片。
int-previousposition=0;
int currentposition=input.indexOf(分隔符);
整块=0;
最后一件=件-1;
while(件<件){
结果[piece++]=输入子字符串(前一位置,当前位置);
前一位置=当前位置+1;
currentposition=input.indexOf(分隔符,前一个位置);
}
结果[件]=输入子串(前一位置);
返回结果;
}
私有静态字符串[]
stringSplitChar(最终字符串输入,
最终炭分离器,
最终整数(最大个数){
如果(maxpieces我想一个很好的理由是他们可以简单地将责任推给正则表达式方法,它为所有字符串方法完成所有真正的繁重工作。我猜他们认为,如果他们已经有了一个可行的解决方案,那么从开发和维护的角度来看,为每个字符串操作重新设计轮子效率会更低重新编译方法。请注意,不需要每次重新编译正则表达式。从:
以str.split(regex,n)
的形式调用此方法会产生与表达式相同的结果
也就是说,如果您担心性能,您可以预编译模式,然后重新使用它:
Pattern p = Pattern.compile(regex);
...
String[] tokens1 = p.split(str1);
String[] tokens2 = p.split(str2);
...
而不是
String[] tokens1 = str1.split(regex);
String[] tokens2 = str2.split(regex);
...
我相信这种API设计的主要原因是方便。由于正则表达式也包含所有“固定”字符串/字符,它将API简化为一个方法而不是几个方法。如果有人担心性能,正则表达式仍然可以按照上面所示预编译
我的感觉(我无法用任何统计证据证明)是大多数情况下String.split()
用于性能不成问题的环境中。例如,这是一次性操作,或者与其他因素相比,性能差异可以忽略不计。在紧密循环中使用同一正则表达式数千次拆分字符串的情况非常罕见,在这种情况下,性能优化确实是有意义的
将带有固定字符串/字符的正则表达式匹配器实现与专用于这些字符串/字符的匹配器实现进行性能比较是很有趣的。差异可能不足以证明单独实现的合理性。在查看Java字符串类时,正则表达式的使用似乎是合理的,并且存在替代方法如果不需要正则表达式:
布尔匹配(字符串正则表达式)
-正则表达式似乎合适,否则您可以使用Pattern p = Pattern.compile(regex);
...
String[] tokens1 = p.split(str1);
String[] tokens2 = p.split(str2);
...
String[] tokens1 = str1.split(regex);
String[] tokens2 = str2.split(regex);
...
Pattern exp = Pattern.compile(":");
String[] array = exp.split(sourceString1);
String[] array2 = exp.split(sourceString2);
s.split(findstr).join(replacestr)