为什么我在BBEdit中的搜索导致"stack overflow"错误?



当我搜索时,我在BBEdit中遇到了一个"堆栈溢出"错误——"堆栈空间不足(应用程序错误代码:12246)"

(@article(((?!eprint|@article|@book).)*r)*)pmid = {(.+)}((((?!eprint|@article|@book).)*r)*(@|r*z))

并替换为

1eprinttype = {pubmed}, eprint = {4}5

我可以手动使用这些相同的模式,每次查找一个&替换,即使不再发生匹配,也不会出现任何错误。我还可以通过处理较小的文件来避免错误。

我怀疑这是我低效和草率的regex编码造成的,我希望专家能帮助我更有效地完成这项工作。我正在尝试查找BibLaTeX目录中尚未具有eprint字段但具有pmid字段的所有条目,并用相应的电子打印规范(使用eprinteprinttype)替换pmid字段。


更新:经过一些实验,我发现只有一种不同的方法才能发挥作用。搜索

(?(?=@article(.+r)+eprint = {(.+r)+}r*)(?!)|(@article(.+r)+)pmid = {(.+)}((.+r)+}r*))

并替换为

3eprinttype = {pubmed}, eprint = {5}6

真的很管用。唯一的问题是backreferences很脆弱,但我无法在BBEdit中使用命名的backreferences。

这可能是由最后一部分引起的灾难性回溯:

.)*r)*(@|r*z))

如果你把它分解并简化,你基本上有一个.*、一个r*和另一个紧挨着的r*。现在在输入的末尾画一个r字符串:每个r应该如何分配?这些小子句中的哪一个会吸收每个r字符?如果你有rrrrr,你可以吃所有五个含有.*成分的r,而不吃任何含有r*成分的。。。或者,你可以组成任意数量的仍然匹配的排列。由于*是贪婪的,它会尝试首先填充.*,但如果失败,它必须继续尝试排列,直到其中一个有效。因此,它可能会通过不必要的回溯占用你的大量资源,直到最终崩溃。

我不是regex优化技术的专家,但如果我是你的话,我会从那里开始。

更新:

查看维基百科上关于PCRE:的文章

除非"NoRecurse"PCRE构建选项(又名"--disable stack for recursion"),则必须有足够的堆栈空间由主叫应用程序或操作系统分配给PCRE。。。。虽然PCRE的文档警告说,"NoRecurse"构建选项使PCRE比其他选项慢,但使用它可以完全避免堆栈溢出的问题。

所以我认为灾难性的回溯是一个很好的选择。在更改PCRE上的构建选项之前,我会尝试通过调整正则表达式来解决这个问题。

显然这是个bug。但你可以试着稍微改变一下表达方式。在不知道需求的情况下很难优化表达式,但这里有一个猜测:

(@article(?:(?:(?!eprint|@article|@book|pmid)[^r])*+r)*+)pmid = {([^nr]+)}((?:(?:(?!eprint|@article|@book)[^r])*+r)*(?:@|r*z))

替换为:

1eprinttype = {pubmed}, eprint = {2}3

BBEdit似乎使用PCRE,除非它(非常)过时,否则上面的表达式应该是兼容的。

最新更新