Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/regex/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Regex 提高正则表达式的效率_Regex_Optimization_Performance_Negative Lookbehind - Fatal编程技术网

Regex 提高正则表达式的效率

Regex 提高正则表达式的效率,regex,optimization,performance,negative-lookbehind,Regex,Optimization,Performance,Negative Lookbehind,我试图通过查找“!”、“?”或“.”来确定英语句子的结尾(仅大致如此),但在“.”的情况下,仅当前面没有常见的缩写词如Mr.或Dr.时 有没有办法使下面的正则表达式更加高效?也许是通过按大小降序,甚至是按字母顺序对负面外观进行排序 下面是我现在使用的正则表达式: ((?<!St|Sgt|Rev|Ltd|Inc|Lt|Jr|Sr|Esq|Inst|Hon|Gen|Cpl|Comdr|Col|Corp|Mr|Dr|Gov|Mrs|Ms|[A-Z]|Assn|Capt)(\.)|(!)|(\?)

我试图通过查找“!”、“?”或“.”来确定英语句子的结尾(仅大致如此),但在“.”的情况下,仅当前面没有常见的缩写词如Mr.或Dr.时

有没有办法使下面的正则表达式更加高效?也许是通过按大小降序,甚至是按字母顺序对负面外观进行排序

下面是我现在使用的正则表达式:

((?<!St|Sgt|Rev|Ltd|Inc|Lt|Jr|Sr|Esq|Inst|Hon|Gen|Cpl|Comdr|Col|Corp|Mr|Dr|Gov|Mrs|Ms|[A-Z]|Assn|Capt)(\.)|(!)|(\?))(\s*$|\s+([_$#]|[A-Z][^.]))
(?
问题是:

该网站在一个简单的段落中报道:“7匹配21044探针(完成)”。21044的惊人大小似乎与负面外观的数量密切相关

我正在寻求降低RegEx引擎的计算复杂性,因为我有几GB的数据要通过它

有没有什么方法可以避免这种情况的发生?负向后看真的是实现这一点的最佳/唯一方法吗?有没有一种方法可以将其作为向前看的替代方法?正则表达式是否是用于此任务的错误工具

编辑:我可以使用ActionScript或PHP的正则表达式引擎

编辑:我不能指望句子之间有多少空格。真的吗?叹气

如果您不了解正则表达式引擎的内部工作原理(与优化相关),请不要回答


提前感谢。

我会先匹配时段。而不是:

(?<!St|Sgt|Rev|Ltd|Inc|...|Capt)\.

…与
[!?]
更改一起,在Regex Powertoy站点上的1404个探测中产生6个匹配项。

可能在成功匹配后只尝试进行负查找测试。而不是针对每个字符:

(?x:  # Allow spacing and comments
    (   
        (\.)    # First match "."
        (?<!    # Then negative-look-behind for titles followed by "."
            (?: St|Sgt|Rev|Ltd|Inc|Lt|Jr|Sr|Esq|Inst|Hon|Gen|Cpl|Comdr|Col|Corp|Mr|Dr|Gov|Mrs|Ms|[A-Z]|Assn|Capt)
            \.
        )
      |  (!)  
      |  (\?)
    )
    ( \s* $  |  \s+ ( [_$#] | [A-Z] [^.] ))
)
(?x:#允许空格和注释
(   
第一场比赛
(?
这使得powertoy.org上使用该网站初始帮助文本的探测数量从70000下降到2500左右(但powertoy不喜欢我的多行正则表达式或“x”标志之类的东西,所以我不得不将正则表达式压缩到一行来测试它)

通过在标题列表中使用常用前缀,您可以更进一步:

(?x:  # Allow spacing and comments
    (
        (\.)    # First match "."
        (?<!    # Then negative-look-behind for titles followed by "."
            (?:Assn|C(?:apt|ol|omdr|orp|pl)|Dr|Esq|G(?:en|ov)|Hon|I(?:nc|nst)|Jr|L(?:t|td)|M(?:[rs]|rs)|Rev|S(?:gt|[rt])|[A-Z])
            \.
        )
      |  (!)  
      |  (\?)
    )
    ( \s* $  |  \s+ ( [_$#] | [A-Z] [^.] ))
)
(?x:#允许空格和注释
(
第一场比赛
(?
这使得探测器的计数下降到2000左右

编辑:
另一个减少探测计数的技巧是在lookbehind部分的开头包含一个大写字母的前瞻(但我不能肯定它是否会使regex更有效)(还包括@Swiss对单词边界的建议):


(?停止压力机!

根据您编辑的问题,您正在为该项目使用PHP或ActionScript,这意味着目前提供的解决方案都没有任何好处。您最初的regex不仅速度太慢,而且在目标平台上根本无法工作。它在regex Powertoy网站上工作的原因是因为该网站使用Java regex风格,w它对lookbehind有更宽松的限制

Lookbehind是正则表达式特性中的一个害群之马;几乎所有的风格都对可以在其中使用的表达式类型施加了限制。例如,在Perl或Python中,表达式必须有一个固定的长度:
(?)将起作用,而
(?)将起作用,但是
(?不会。Java更为宽松;它接受可变长度的lookback表达式,只要可以提前确定最大可能长度,因此
(?将起作用,
(?)也会起作用,但是
(?不会

PHP和ActionScript正则表达式的风格都是由PCRE库提供支持的,PCRE库在lookbehinds方面比Perl和Python稍微宽松一点。如果lookbehind表达式是一个替代表达式,则每个替代表达式的长度仍然必须是固定的,但它们不必都具有相同的长度。但这只允许在to中使用正则表达式的p“level”——也就是说,lookback既不能包含另一个分组构造,也不能包含在一个分组构造中

这就是目前为止提供的所有解决方案都无法运行的原因。为了绕过分组限制,我必须将对
的检查组合到
[.!?]
中,并将
\b
.
分配到备选方案中,从而导致

/([.!?])(?<!\bSt\.|\bSgt\.|\bRev\.|\bLtd\.|\bInc\.|\bLt\.|\bJr\.|\bSr\.|\bEsq\.|\bInst\.|\bHon\.|\bGen\.|\bCpl\.|\bComdr\.|\bCol\.|\bCorp\.|\bMr\.|\bDr\.|\bGov\.|\bMrs\.|\bMs\.|\b[A-Z]\.|\bAssn\.|\bCapt\.)(?:\s*$|\s+(?:[_$#]|[A-Z][^.]))/
/([.!?])(?
这使探针计数达到了2208,这仍然比您开始时的计数高出一个数量级。对于您的几GB文本,这是否足够快,我不知道

编辑:在您的评论中,您建议按长度对标题进行分组,但这不起作用。但是,更进一步,我将这些分组放在各自的lookback中,而且(令我惊讶的是)这似乎起到了作用。以下是在自由间距模式下的效果:

/(?:
   \.
     (?<!\bComdr\.)
     (?<!(?=\b[A-Z])(?:Assn|C(?:apt|orp)|Inst)\.)
     (?<!(?=\b[A-Z])(?:C(?:ol|pl)|Esq|G(?:en|ov)|Hon|Inc|Ltd|Mrs|Rev|Sgt)\.)
     (?<!(?=\b[A-Z])(?:Dr|Jr|Lt|M[rs]|S[rt])\.)
     (?<!\b[A-Z]\.)
   |
   [!?]
 )
 (?:\s*$|\s+(?:[_$#]|[A-Z][^.]))
/x
/(?)
\.
(?

要查看它的实际效果,请查看。

使用“向后看”表明它一定是NFA引擎。您是否考虑过通过标点符号后面的内容来评估句子结尾?如果您的文本总是用两个空格分隔句子,那么这种方法在缩写词上遇到麻烦的可能性似乎比您列出的方法要小。(耸耸肩)为什么不分析一些常见的假设?你可以用一个单词边界来进一步优化它。把它放在“?:”后面,并用括号括起来。我认为你的最新编辑,没有单词边界的情况下,它实际上更快。当我在PHP中使用这个精彩的(严肃的!)示例时,它告诉我“lookbehind断言不是固定长度的”。我想这是因为你的量子伏都教在交替中…既然可变长度lookbehind在PHP中是一个禁忌,有没有简单的解决方法?@Joshua:你可以让每个备选方案成为一个单独的负向lookbehind(或者分组成相同长度的备选方案)。如(?我唯一的问题是它似乎将“?”和“!”与“.”组合在一起。我希望这个句子肯定以?或!结尾,而我希望以“.”结尾
        (?<!   # Then negative-look-behind for titles followed by "."
               \b (?= [A-Z] )  # But first ensure we have a capital letter before going on
               (?:Assn|C(?:apt|ol|omdr|orp|pl)|Dr|Esq|G(?:en|ov)|Hon|I(?:nc|nst)|Jr|L(?:t|td)|M(?:[rs]|rs)|Rev|S(?:gt|[rt])|[A-Z])
            \.
        )
/([.!?])(?<!\bSt\.|\bSgt\.|\bRev\.|\bLtd\.|\bInc\.|\bLt\.|\bJr\.|\bSr\.|\bEsq\.|\bInst\.|\bHon\.|\bGen\.|\bCpl\.|\bComdr\.|\bCol\.|\bCorp\.|\bMr\.|\bDr\.|\bGov\.|\bMrs\.|\bMs\.|\b[A-Z]\.|\bAssn\.|\bCapt\.)(?:\s*$|\s+(?:[_$#]|[A-Z][^.]))/
/(?:
   \.
     (?<!\bComdr\.)
     (?<!(?=\b[A-Z])(?:Assn|C(?:apt|orp)|Inst)\.)
     (?<!(?=\b[A-Z])(?:C(?:ol|pl)|Esq|G(?:en|ov)|Hon|Inc|Ltd|Mrs|Rev|Sgt)\.)
     (?<!(?=\b[A-Z])(?:Dr|Jr|Lt|M[rs]|S[rt])\.)
     (?<!\b[A-Z]\.)
   |
   [!?]
 )
 (?:\s*$|\s+(?:[_$#]|[A-Z][^.]))
/x