提高 PCRE 正则表达式模式的性能
Improving the performance of an PCRE Regex Pattern
我这里有下面的正则表达式,它是为支持 PRCE/PRCE2 格式而编写的。但是,这会引发以下错误 “评估时间过长。请检查您的正则表达式。”我们是否可以通过简化此正则表达式来提高性能?
此外,正则表达式也会抛出 “灾难性回溯” 错误。
(\border\D*\W*)\d+(*SKIP)(*F)|(\border\D*number\W*)\d+(*SKIP)(*F)|(?<!x)(?=(?:[._ –-]*\d){9})(?!9|66\D*6|00\D*0|(?:\d\D*){3}0\D*0|(?:\d\D*){5}0(?:\D*0){3})\d(?:[._ –-]*\d){4}
上面的正则表达式中有一组规则。请找到正则表达式的要求。
- 前 5 个号码只能被屏蔽在 9 位号码中。
- 如果 'x' 或 'X' 位于 9 位数字之前,则不应屏蔽任何数字。
- 如果“订单”或“订单号”字符串在 9 位数字之前,则不应匹配。
- 您可以在此 link 中找到相同的用例列表以及规则。 Usecases with requirements
Regex101 为我提供了预期的准确输出,但它存在性能问题。需要简化一下。
您可以试试这个重构的正则表达式:
\b(?>x|order(?>[\W_]*number)?[\W_]*)\d+(*SKIP)(*F)|(?=(?>[._ –-]*\d){9})(?>(?>9|6{3}|0{3}|(?>\d\D*){3}00|(?>\d\D*){5}0{4})(*SKIP)(*F)|\d(?>\D*\d){4})
与您现有的演示 link 相比,它在演示 link 中花费了几乎一半的步骤。
其他方法:扩展模式!
~(*UTF)
x (?<! \w x ) [\d._ –-]* (*SKIP) (*F)
|
order (?<! \w order ) [\W_]* (?:number)? [\W_]* [\d._ –-]* (*SKIP) (*F)
|
(?<res>
[1-578] (?: [._ –-]{0,3}+ \d ){2} (?: 0{2} [\d._ –-]* (*SKIP) (*F) )?
(?: [._ –-]{0,3}+ \d ){2}
)
(?: 0{4} [\d._ –-]* (*SKIP) (*F) )? (?: [._ –-]{0,3}+ \d ){4}
|
(?<res>
0 (?: 0{2} [\d._ –-]* (*SKIP) (*F) )? (?: [._ –-]{0,3}+ \d ){2}
(?: 0{2} [\d._ –-]* (*SKIP) (*F) )? (?: [._ –-]{0,3}+ \d ){2}
)
(?: 0{4} [\d._ –-]* (*SKIP) (*F) )? (?: [._ –-]{0,3}+ \d ){4}
|
(?<res>
6 (?: 6{2} [\d._ –-]* (*SKIP) (*F) )? (?: [._ –-]{0,3}+ \d ){2}
(?: 0{2} [\d._ –-]* (*SKIP) (*F) )? (?: [._ –-]{0,3}+ \d ){2}
)
(?: 0{4} [\d._ –-]* (*SKIP) (*F) )? (?: [._ –-]{0,3}+ \d ){4}
|
9 [\d._ –-]* (*SKIP) (*F)
~iJx
花样确实比较长,但是2 times faster and with 8 times fewer steps.
注意我用了一个capture group来提取前5位,剩下的4位也被消耗了,但是如果你愿意,你也可以去掉这个capture group,把剩下的4位放在lookahead中(more steps but more efficient).
我从 (*UTF)
开始模式,因为它包含一个超出 ascii 范围的破折号。
我这里有下面的正则表达式,它是为支持 PRCE/PRCE2 格式而编写的。但是,这会引发以下错误 “评估时间过长。请检查您的正则表达式。”我们是否可以通过简化此正则表达式来提高性能?
此外,正则表达式也会抛出 “灾难性回溯” 错误。
(\border\D*\W*)\d+(*SKIP)(*F)|(\border\D*number\W*)\d+(*SKIP)(*F)|(?<!x)(?=(?:[._ –-]*\d){9})(?!9|66\D*6|00\D*0|(?:\d\D*){3}0\D*0|(?:\d\D*){5}0(?:\D*0){3})\d(?:[._ –-]*\d){4}
上面的正则表达式中有一组规则。请找到正则表达式的要求。
- 前 5 个号码只能被屏蔽在 9 位号码中。
- 如果 'x' 或 'X' 位于 9 位数字之前,则不应屏蔽任何数字。
- 如果“订单”或“订单号”字符串在 9 位数字之前,则不应匹配。
- 您可以在此 link 中找到相同的用例列表以及规则。 Usecases with requirements
Regex101 为我提供了预期的准确输出,但它存在性能问题。需要简化一下。
您可以试试这个重构的正则表达式:
\b(?>x|order(?>[\W_]*number)?[\W_]*)\d+(*SKIP)(*F)|(?=(?>[._ –-]*\d){9})(?>(?>9|6{3}|0{3}|(?>\d\D*){3}00|(?>\d\D*){5}0{4})(*SKIP)(*F)|\d(?>\D*\d){4})
与您现有的演示 link 相比,它在演示 link 中花费了几乎一半的步骤。
其他方法:扩展模式!
~(*UTF)
x (?<! \w x ) [\d._ –-]* (*SKIP) (*F)
|
order (?<! \w order ) [\W_]* (?:number)? [\W_]* [\d._ –-]* (*SKIP) (*F)
|
(?<res>
[1-578] (?: [._ –-]{0,3}+ \d ){2} (?: 0{2} [\d._ –-]* (*SKIP) (*F) )?
(?: [._ –-]{0,3}+ \d ){2}
)
(?: 0{4} [\d._ –-]* (*SKIP) (*F) )? (?: [._ –-]{0,3}+ \d ){4}
|
(?<res>
0 (?: 0{2} [\d._ –-]* (*SKIP) (*F) )? (?: [._ –-]{0,3}+ \d ){2}
(?: 0{2} [\d._ –-]* (*SKIP) (*F) )? (?: [._ –-]{0,3}+ \d ){2}
)
(?: 0{4} [\d._ –-]* (*SKIP) (*F) )? (?: [._ –-]{0,3}+ \d ){4}
|
(?<res>
6 (?: 6{2} [\d._ –-]* (*SKIP) (*F) )? (?: [._ –-]{0,3}+ \d ){2}
(?: 0{2} [\d._ –-]* (*SKIP) (*F) )? (?: [._ –-]{0,3}+ \d ){2}
)
(?: 0{4} [\d._ –-]* (*SKIP) (*F) )? (?: [._ –-]{0,3}+ \d ){4}
|
9 [\d._ –-]* (*SKIP) (*F)
~iJx
花样确实比较长,但是2 times faster and with 8 times fewer steps.
注意我用了一个capture group来提取前5位,剩下的4位也被消耗了,但是如果你愿意,你也可以去掉这个capture group,把剩下的4位放在lookahead中(more steps but more efficient).
我从 (*UTF)
开始模式,因为它包含一个超出 ascii 范围的破折号。