【发布时间】:2020-11-17 10:32:00
【问题描述】:
我的前任编写的这个大 reg 模式遇到了灾难性的回溯问题。 我们基本上只是想从职位描述中过滤掉薪水。
这是模式:
(?:(?:(?:\bEURO|\bEuro|\beuro|\bEUR|\bEur|\beur|€)[[:punct:]]?\W*(?:(?<!\d)(?:(\d{1,3}(?:[,.\'\s])\d{3})|([12]?\d{3,5}))(?!\d)(?:[,.](?:\d\d|-|--))?))|(?:(?:(?<!\d)(?:(\d{1,3}(?:[,.\'\s])\d{3})|([12]?\d{3,5}))(?!\d)(?:[,.](?:\d\d|-|--))?)(?:\W*(?:\bEURO|\bEuro|\beuro|\bEUR|\bEur|\beur|€))))|(?:(?:(?:gehalt|lohn|entgelt|netto|brutto|überzahlung|kollektivvertrag|wage\W|salary)\w*\W+(?:[a-zA-Z[:punct:]]+\W+){0,6}(?:(?<!\d)(?:(\d{1,3}(?:[,.\'\s])\d{3})|([12]?\d{3,5}))(?!\d)(?:[,.](?:\d\d|-|--))?))|(?:(?:(?<!\d)(?:(\d{1,3}(?:[,.\'\s])\d{3})|([12]?\d{3,5}))(?!\d)(?:[,.](?:\d\d|-|--))?)(?:\w*\W+){0,6}\w*(?:gehalt|lohn|entgelt|netto|brutto|überzahlung|kollektivvertrag|wage\W|salary)))
它基本上完成了它打算做的事情,但是在我的 Java 应用程序中,它会导致一些 Job 字符串冻结。那一定不能发生。
我几乎可以肯定,这可以做得更容易,而且要好一百倍,我只是没有时间学习高级的正则表达式。也许一些专业人士对如何防止灾难性的回溯问题有一个快速的、第一眼的想法并帮助我。
它应该能识别出类似的模式
Eur 40.000
<some random text>gehalt: 2000-3000
(两个数值,因此我可以进一步处理以确定最小值/最大值)
2000 - 50.000 euro
等等
例子:
输入:
We offer a salary of 40.000 - 50.000.
匹配:
40.000 , 50.000
输入:
date: 12.10.2020 - We offer eur 3000 - 20.000.
匹配:
3000 , 20.000
输入:
Hello world ! Today is: 12.10.2020 - We offer a Gehalt of eur3000-20.000
匹配:
3000 , 20.000
问题出现在疯狂的字符串中,例如 Crazy String that unfortunately can occur during a web crawl
【问题讨论】:
-
新造币“cacktracking”的积分,但我觉得不得不将其更改为常规的既定术语。
-
很难猜测像
(?<!\d)(?:(\d{1,3}(?:[,.\'\s])\d{3})|([12]?\d{3,5}))(?!\d)(?:[,.](?:\d\d|-|--))?这样的重复片段真正应该捕捉到什么。可以猜到你希望正则表达式的意思,但如果你能把它拼出来就更好了。 -
感谢您的示例。不过,您的第一个示例似乎实际上并不匹配。见regex101.com/r/ZflJFQ/1
-
确实没有,但目前这是次要问题。我主要担心程序不会因为灾难性的回溯而冻结。我将发布一个示例字符串:regex101.com/r/BGXYdP/1 这样的字符串永远不会发生......但不幸的是它们可能会发生......
-
我没有看到很多回溯的机会,尽管例如
(?:\bEURO|\bEuro|\beuro|\bEUR|\bEur|\beur|€)[[:punct:]]?\W*(?:(?<!\d)非常多余。[[:punct:]]与\W重叠,因此如果匹配在消耗标点符号时失败,则正则表达式引擎必须尝试将每个标点符号匹配为\W,这会引入一些但肯定不会 - 孤立地 - 灾难性的回溯。(?:\b(?:EURO?|[Ee]uro?)|€)\W*更简洁地匹配相同的字符串,无需回溯((?<!\d)是多余的,因为无论如何匹配都不能是数字)。
标签: regex backtracking