停止印刷机!
根据您编辑的问题,您正在为该项目使用 PHP 或 ActionScript,这意味着到目前为止提供的解决方案都没有任何用处。您的原始正则表达式不仅太慢,而且在目标平台上根本不起作用。它在 Regex Powertoy 站点上运行的原因是因为该站点使用 Java regex 风格,它对lookbehinds 有更宽松的限制。
Lookbehind 是正则表达式功能中的害群之马;几乎所有的风格都对你可以在其中使用的表达方式施加了限制。例如,在 Perl 或 Python 中,表达式必须有一个固定的长度:(?<!St)
will work 和 will 一样(?<!Sgt|Rev)
,但(?<!St|Sgt)
不会。Java 更加宽松;只要可以提前确定最大可能长度,它就接受可变长度的后向表达式,因此(?<!St|Sgt)
可以正常工作,(?<!\w{3,12})
但(?<!\w+)
不会。
PHP 和 ActionScript 正则表达式风格都由 PCRE 库提供支持,就后向搜索而言,它比 Perl 和 Python 稍微宽松一点。如果lookbehind 表达式是一个替代,每个替代的长度仍然必须是固定的,但它们不必都具有相同的长度。但这仅在正则表达式的顶级“级别”中被允许——也就是说,lookbehind 既不能包含另一个分组结构,也不能包含在一个分组结构中。
这就是使迄今为止提供的所有解决方案都不可行的部分。为了绕过分组限制,我不得不将 和 into 的检查结合起来,并.
在备选方案中分配and ,导致!
?
[.!?]
\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 文本,这是否足够快,我不知道。
编辑:在您的评论中,您建议按长度对标题进行分组,但没有奏效。但是,更进一步,我将这些组中的每一个放在自己的后面,并且(令我惊讶的是)这似乎确实有效。以下是它在自由间距模式下的外观:
/(?:
\.
(?<!\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
要查看它的实际效果,请查看ideone.com 上的 PHP 演示。