前:我正试图使用regexp从一个大数组中提取不同类型的parts
。该操作在AsyncTask
中执行。part.plainname
是一个字符串,最多256个字符。item_pattern
看起来像"^keyword.*?$"
问题:我找到了一种方法,它减缓了一切:
public int defineItemAmount(NFItem[] parts, String item_pattern){
System.out.println("STAMP2");
int casecount = 0;
for (NFItem part : parts) {
if (testItem(part.plainname, item_pattern))
++casecount;
}
System.out.println("STAMP3");
return casecount;
}
public boolean testItem(String testString, String item_pattern){
Pattern p = Pattern.compile(item_pattern);
Matcher m = p.matcher(testString);
return m.matches();
}
只有950个parts
,但它的工作速度非常慢:
02-25 11:34:51.773 1324-1343/com.nfe.unsert.dns_pc_creator I/System.out﹕ STAMP2
02-25 11:35:18.094 1324-1343/com.nfe.unsert.dns_pc_creator I/System.out﹕ STAMP3
20秒只是为了计数。testItem
被大量使用,大约为15*parts
。因此,整个应用程序的工作时间超过15分钟。而几乎相同的java程序(不适用于android应用程序)在不到30秒内完成。
问题:我做错了什么?为什么简单的regexp操作需要这么长时间?
您可以预编译模式:
public static int defineItemAmount(NFItem[] parts, String item_pattern){
System.out.println("STAMP2");
Pattern pattern = Pattern.compile(item_pattern);
int casecount = 0;
for (NFItem part : parts) {
if (testItem(part.plainname, pattern))
++casecount;
}
System.out.println("STAMP3");
return casecount;
}
public static boolean testItem(String testString, Pattern pattern){
Matcher m = pattern.matcher(testString);
return m.matches();
}
如果您正在寻找以关键字开头的字符串,则不需要将matches
方法与这种模式^keyword.*?$
:一起使用
- 首先,非贪婪的量词是无用的,可能会让正则表达式引擎毫无进展,贪婪的量词会给你同样的结果
- 由于默认情况下
matches
方法是锚定的,因此不需要锚定,因此可以删除它们 - 您只对字符串的开头感兴趣,所以在这种情况下,
lookingAt
方法更合适,因为它不关心字符串末尾发生的事情 - 正如其他答案所注意到的,如果多次使用相同的模式,请尝试在testItem函数之外一次性编译它。但如果不是这样,就不要编译它
- 如果
keyword
是一个文本字符串而不是子模式,则根本不要使用regex,而是使用indexOf
来检查关键字是否在索引0处
您不需要每次都编译模式。相反,在初始化时只做一次。
但是,由于它们的通用性,正则表达式的速度并不快,而且它们也不是为之设计的。如果数据足够规则,那么使用特定的字符串拆分技术可能会更好。
-
正则表达式通常慢,因为它们的构造涉及很多事情(如同步)。
-
不要在循环中调用单独的方法(这可能会阻止某些优化)。让VM优化for循环。使用这个并检查性能:
Pattern p = Pattern.compile(item_pattern); // compile pattern only once for (NFItem part : parts) { if (testItem(part.plainname, item_pattern)) ++casecount; } Matcher m = p.matcher(testString); boolean b = m.matches(); ...