我建议您在不使用回顾断言的情况下搜索分隔标点,然后释放这些匹配的字符(使用
\K
),然后匹配空格,最后向前查找大写字母以表示下一个句子的开始。
代码:(
演示)
$str = 'Fry me a Beaver. Fry me a Beaver! Fry me a Beaver? Fry me Beaver no. 4?! Fry me many Beavers... End';
var_export(
preg_split('~[.?!]+\K\s+(?=[A-Z])~', $str, 0, PREG_SPLIT_NO_EMPTY)
);
输出:
array (
0 => 'Fry me a Beaver.',
1 => 'Fry me a Beaver!',
2 => 'Fry me a Beaver?',
3 => 'Fry me Beaver no. 4?!',
4 => 'Fry me many Beavers...',
5 => 'End',
)
虽然不需要对示例字符串进行处理,但使用PREG_SPLIT_NO_EMPTY
可以防止在数组末尾创建空元素,如果字符串以标点符号结尾。
在我的回答中使用 \K
可以减少回溯。这使得正则表达式引擎在扫描字符串时更加高效。在 Hamza 的回答中,正则表达式引擎每次匹配到空格时开始匹配,然后在匹配空格后,需要向后读取来检查标点符号,然后如果符合条件,它还需要向前查找字母。
在我的方法中,当正则表达式引擎遇到列出的标点符号之一时,才开始考虑匹配,并且它永远不会回溯。有许多空格要匹配,但较少的符号符合条件。因此,在示例输入字符串上,我的模式将字符串分成40个步骤,而Hamza 的模式将字符串分成74个步骤。
这种效率在相对较小的字符串上并没有太大的优势,但是,如果您正在解析大型文本,则效率和最小化回溯变得更加重要。
终止符
类-用于标记句子的结尾。如果你将其中一个终止符号用作普通符号,那么它要么不是终止符,要么你在错误地组成句子。简单来说,你不能两全其美。 - Shark