在正则表达式中使用通配符会导致低效扫描

时间:2016-07-14 21:09:16

标签: java regex

我有一个文本文件(大小为7GB以上),其中包含重复的行,如下所示:10.00和2.00可能每行不同:

startline money earned 10.00 "300 plus nums n words here" money start 2.00 more words

我想获取值10.00和2.00

我的正则表达式如下:

money earned ([0-9\.]+).*money start ([0-9\.]+)

但这是非常低效的。我花了将近30分钟来扫描1%的文本文件!似乎.*导致了这种低效率。因此,我选择使用2个单独的正则表达式行来获取这些值,如下所示,这样做效果也更好。

money earned ([0-9\.]+) //this is line 1 capturing 10.00
money start ([0-9\.]+)  //this is line 2 capturing 2.00

但这导致赚取的钱(10.00)首先被捕获,因为它是每一行的第一部分而货币开始(2.00)最终成为第二。

我希望扭转这种局面,并且能够首先捕获每条线的货币开始(2.00),然后获得赚取的钱(10.00)。有没有什么方法可以反转正则表达式从行的后面开始并移动到前面。或者,无论如何,当使用单行正则表达式进行扫描时,我可以克服效率低下的问题?

2 个答案:

答案 0 :(得分:0)

您是否能够在Java程序接管之前预处理文件?

我使用您的示例作为模板创建了一个7.1 GB的文件。然后我使用grep对其进行预处理,以创建一个中间文件,然后可以更容易地由java处理。

time grep -Eo 'money (earned|start) \d+\.\d+' large_file.txt > results.txt

real    3m12.306s
user    3m7.701s
sys     0m3.222s

results.txt文件只花了大约三分钟创建,只有168M,格式为:

money earned 10.00
money start 2.00
money earned 10.00
money start 2.00 
money earned 10.00
money start 2.00

答案 1 :(得分:0)

money earned ([0-9\.]+).*money start ([0-9\.]+)
                       ^^

有你的问题。这是贪心匹配。这意味着它会在回溯之前开始匹配,并尝试更短的匹配以允许其余的正则表达式匹配。因此,如果你有很多的数据,或者很长的行(甚至很长的字符串,取决于.是否可以匹配换行符),这可能需要一段时间。它还取决于您的数据的样子。如果在最后money start之后有大量文字出现,则需要更长时间。如果行中有多个money start,则跳过除最后一个之外的所有内容。

您可以尝试使用.*?,这是 lazy 匹配,也就是说,它以 little 开头并扩展它。在许多情况下,这要快得多。