【发布时间】:2015-11-23 11:07:57
【问题描述】:
我正在尝试从线程转储文件中获取线程名称。 线程名称通常包含在每个线程转储的第一行的“双引号”中。 它可能看起来很简单:
"THREAD1" daemon prio=10 tid=0x00007ff6a8007000 nid=0xd4b6 runnable [0x00007ff7f8aa0000]
或者大到如下:
"[STANDBY] ExecuteThread: '43' for queue: 'weblogic.kernel.Default (self-tuning)'" daemon prio=10 tid=0x00007ff71803a000 nid=0xd3e7 in Object.wait() [0x00007ff7f8ae1000]
我写的正则表达式很简单:"(.*)"。它将双引号内的所有内容作为一个组捕获。然而,它会导致大量的回溯,因此需要很多步骤,如here 所示。口头上我们可以将这个正则表达式解释为 “将包含在双引号内的任何内容作为一个组捕获”
所以我想出了另一个执行相同的正则表达式:"([^\"])"。口头上我们可以将此正则表达式描述为 “捕获任意数量的包含在双引号内的非双引号字符”。我没有找到比这更快的正则表达式。它不执行任何回溯,因此它需要最少的步骤,如 here 所示。
我在上面告诉了我的同事。他想出了另一个:"(.*?)"。我不明白它是如何工作的。它执行的回溯比第一个要少得多,但比第二个要慢一点,如here 所示。
不过
- 我不明白为什么回溯会提前停止。
- 我知道
?是一个量词,意思是once or not at all。但是我不明白once or not at all在这里是如何使用的。 - 事实上,我无法猜测我们如何口头描述这个正则表达式。
我的同事试图解释我,但我仍然无法完全理解。谁能解释一下?
【问题讨论】:
-
是否需要匹配
"+substring having no quote+"之类的子字符串? -
我认为你应该使用
.*?这会使搜索变得懒惰。我认为您当前的正则表达式存在缺陷。如果线程名称后面的行中有"some text here",则最后一个"将被映射。 -
@VinodMadyalkar:您建议的是效率最低的解决方案之一。惰性匹配有一些非常重要的缺点。否定字符类解决方案是最好的。
-
@stribizhev - 但是看看字符串,贪婪会涉及很多回溯。如果线程名称后面还有另一个
""怎么办? Thread 名称从 String 的开头开始,值得回溯吗? -
@VinodMadyalkar:
"([^"]*+)"是匹配"no-quotes-here"类字符串的最佳正则表达式。
标签: java regex performance