在使用PHP的explode或其他类似函数时,是否有方法可以保留分隔符?

28
例如,我有一篇文章应该根据句子边界拆分,例如".","?","!"和":"。但是我们都知道,无论是preg_split还是explode函数,它们都会删除定界符。任何帮助将不胜感激!编辑:我只能想到下面的代码,虽然它非常有效。
$content=preg_replace('/([\.\?\!\:])/',"\\1[D]",$content);

谢谢!!! 大家。仅用五分钟就得到了 3 个答案!我必须为在提问之前没有仔细阅读 PHP 手册而道歉。抱歉。


更好的 [mcve] 在这里:将文本拆分成句子 - mickmackusa
5个回答

27

我认为这值得添加。你可以使用正则表达式预查来分割,从而在“after”字符串中保留分隔符:

$input = "The address is http://stackoverflow.com/";
$parts = preg_split('@(?=http://)@', $input);
// $parts[1] is "http://stackoverflow.com/"
如果分隔符长度固定,你可以使用lookbehind将分隔符保留在“before”部分中:
$input = "The address is http://stackoverflow.com/";
$parts = preg_split('@(?<=http://)@', $input);
// $parts[0] is "The address is http://"

在大多数情况下,这个解决方案更简单、更清晰。


1
你甚至可以这样使用多个分隔符:preg_split('@(?=(http://|https://))@', $input)(保存在 "after" 中) - TheStoryCoder

19

使用preg_split函数时,你可以设置PREG_SPLIT_DELIM_CAPTURE标志,并捕获定界符。然后你可以将每一对2n和2n+1重新组合在一起:

$parts = preg_split('/([.?!:])/', $str, -1, PREG_SPLIT_DELIM_CAPTURE);
$sentences = [];
for ($i = 0, $n = count($parts) - 1; $i <= $n; $i += 2) {
    $sentences[] = $parts[$i] . ($parts[$i+1] ?? '');
}

请注意将分隔符包装成一个组,否则它们不会被捕获。


1
正是我想做的事情...但我太懒了,不想打 :-) - Juergen Schulze
请注意,当使用非特定的标记(例如\d、\s)时,此方法无法正常工作,因为它们不会被捕获。 - zed

18

preg_split使用PREG_SPLIT_DELIM_CAPTURE标志。

例如:

$parts = preg_split("/([\.\?\!\:])/", $string, -1, PREG_SPLIT_DELIM_CAPTURE);

0

解析英语句子有很多微妙之处和边缘情况。这使得编写完美的解析器非常困难。使用您的真实项目数据进行足够的测试用例非常重要,以确保您覆盖了所有情况。

对于此任务,无需使用lookarounds或捕获组。您只需匹配标点符号,然后使用\K忽略它们,然后匹配出现在句子之间的一个或多个空格字符。使用PREG_SPLIT_NO_EMPTY标志可防止创建空元素,如果您的字符串以或以满足模式的字符结尾,则不会创建空元素。

代码:(演示)

$str = 'Heading: This is a string. Very exciting! What do you think? ...one more thing, this is cool.';

var_export(
    preg_split('~[.?!:]+\K\s+~', $str, 0, PREG_SPLIT_NO_EMPTY)
);

输出:

array (
  0 => 'Heading:',
  1 => 'This is a string.',
  2 => 'Very exciting!',
  3 => 'What do you think?',
  4 => '...one more thing, this is cool.',
)

0

试试T-Regx

<?php
$parts = pattern('([.?!:])')->split($string);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接