如何在 preg_split() 的结果中包含分隔符?

31

我有一个简单的模式,可以将文本按句号分割:

$text = preg_split("/[\.:!\?]+/", $text);

但是我想在数组项的末尾包含. :

也就是说,现在对于"good:news.everyone!",我有:

array("good", "news", "everyone", "");

但我想要:

array("good:", "news.", "everyone!", "");
2个回答

63

这是你需要的:

preg_split('/([^.:!?]+[.:!?]+)/', 'good:news.everyone!', -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);

工作原理:该模式实际上将所有内容转换为分隔符。然后,要将这些分隔符包含在数组中,您可以使用PREG_SPLIT_DELIM_CAPTURE常量。这将返回如下的数组:

array (
    0 => '',
    1 => 'good:',
    2 => '',
    3 => 'news.',
    4 => '',
    5 => 'everyone!',
    6 => '',
);

要去除空值,请使用PREG_SPLIT_NO_EMPTY。 要组合两个或多个这些常量,我们使用按位|运算符。结果:

array (
    0 => 'good:',
    1 => 'news.',
    2 => 'everyone!'
);

如果我需要将“good:”作为整个单词与冒号分开怎么办? 我能否添加<strong>标签呢?所以我需要的是<strong>Good:</strong> - user1551496
2
@user1551496:那么你正在处理标记。请使用解析器而不是正则表达式,因为正则表达式无法很好地处理标记 - Elias Van Ootegem
1
@NinoŠkopac:[^.:!?]+ 贪婪地匹配除了 .:!? 之外的所有字符,接下来的字符组贪婪地匹配 .:!? 一次或多次。这两个字符类被分组,因为模式将它们包裹在 () 中,所以结果是你匹配了所有内容。然而,当遇到一个或多个 .:!? 时,匹配就会结束,并且下一个匹配会被放置在一个新的组中,因此数组 -> 匹配、空、匹配、空... 使用 PREG_SPLIT_DELIM_CAPTURE,可以确保用作分隔符的匹配项在数组中,PREG_SPLIT_NO_EMPTY 可以去掉空位。 - Elias Van Ootegem
1
基本上,字符串中的每个部分都是一个分隔符,并且您正在拆分空字符串。您忽略空字符串并要求 preg_split 给您匹配的分隔符,这就是 OP 想要的。 - Elias Van Ootegem

11

如果您在正则表达式中使用了正向后查找,则不需要使用PREG_SPLIT_DELIM_CAPTURE。该函数将保留分隔符。

$text = preg_split('/(?<=[.:!?])/', 'good:news.everyone!', 0, PREG_SPLIT_NO_EMPTY);
如果您使用`lookbehind`,它只会查找字符而不匹配它。所以,在`preg_split()`的情况下,该函数不会丢弃该字符。
没有`PREG_SPLIT_NO_EMPTY`标志的结果:
array (
    0 => 'good:',
    1 => 'news.',
    2 => 'everyone!',
    3 => ''
);

使用 PREG_SPLIT_NO_EMPTY 标记的结果如下:

array (
    0 => 'good:',
    1 => 'news.',
    2 => 'everyone!'
);
你可以使用这个PHP在线函数测试器来进行测试。

1
你也可以使用正向先行断言 ?= 而不是 ?<=,这样分隔符总是会在下一个匹配项 'good',':news','everyone!' 中结束。 - Jonathan DS
@JonathandosSantos 这很方便。谢谢! - Thanasis

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