如何在使用preg_replace时保持某些字符完好无损?

时间:2014-10-31 18:22:31

标签: php regex preg-replace

处理一些文本格式和分析 - 我有一大块文本,我试图分成单个句子。显然,explode可以使用每个句子末尾的标点符号来轻松完成。

我遇到的问题是,普通语言还包含不表示句子结尾的句点 - 例如小数和缩写。例如,“一支团队预计他们将打破以前创纪录的92.49%的效率,这是1991年制定的。”将导致两个句子,第二个句子以“49%”开头。这就是我要避免的。

我可以安全地删除这些句子中期而不影响我的分析,但我需要保持每个字符串的其余部分完整 - 这就是我遇到麻烦的地方。在上面小数点的情况下,我可以将字符与$str = preg_replace("/[\.]+[0-9]/", "", $str);匹配 - 但是替换匹配也会消除该数字的第一个小数。

如何使用preg_replace并保持某些字符完好无损?


更新

一些答案​​建议使用前瞻来匹配角色而不将其包含在替换中。虽然这适用于上面给出的例子,但这不适用于缩写(例如美国) - 是否有更普遍的情况我们可以提出,或者至少可能是对应的“看后”?

5 个答案:

答案 0 :(得分:0)

如果你调整你的正则表达式以匹配数字围绕小数的位置怎么办...这样的话可能

/[0-9]+[\.][0-9]+/

修改

匹配然后替换?

preg_match_all("/[0-9]+[\.][0-9]+/", $str, $out, PREG_PATTERN_ORDER);

然后遍历$ out数组并对这些字符串执行替换以删除小数。

答案 1 :(得分:0)

我认为这应该适合你:

[\.](?=[0-9])

它使用前瞻来匹配小数后跟0-9,但不包括匹配中的0-9。

更新:

我考虑到您的更新后又看了一眼,但我无法想到解决所有用例的解决方案。我能够提出一个更为通用的解决方案来覆盖更多情况:

[\.](?=[^\s])

这会查找一个句点或小数点后跟任何不是空格,制表符,换行符等的字符,而不是后面跟一个数字。这有助于捕捉可能导致问题的更多事情,但它仍然遗漏了很多。

这适用于以下内容:

“一支团队预计他们将打破以前创纪录的92.49%的效率,这是1991年在美国设定的。”

但是会因为这样的事情而失败:

“一支团队预计他们将打破以前创纪录的92.49%效率,这是1991年在美国设定的。”

正如@vrijdenker所提到的,名字将是另一个问题。我只是不知道你如何区分一个句子结尾的句号和一个缩写的中间名词之后的句号。

答案 2 :(得分:0)

尝试:

$str = preg_replace("/\.(?=\d)/", "", $str);

答案 3 :(得分:0)

由于您不想只忽略属于某个数字的点,还要忽略缩写,名称等,只需暂时忘记这些数字。

我已经设置了一个包含一些Lorem Ipsum的小提琴,在中间我添加了你的例句,后面加了一些缩写和一个名字。

<?php


$var = <<<EOT
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam tortor velit, facilisis ac malesuada vel, tristique sit amet purus.
Donec magna turpis, iaculis vitae nisl et, porttitor tincidunt augue. Fusce odio tortor, laoreet ut turpis eget, lobortis ultrices lorem.
One team anticipates they will break the previous record of 92.49% efficiency, which was set in 1991. B.T.W.: abbreviations like U.S. and names like I.M. Theman should also be ignored.
Duis lobortis lacus ligula, a lobortis ipsum lacinia in. Suspendisse potenti. Donec mattis volutpat nisi, non cursus est. Nam pellentesque congue lectus, in auctor erat viverra sit amet. 
Mauris pellentesque magna dolor, in euismod neque mattis eu. Etiam in massa eget eros consectetur iaculis eu in tortor. 
Mauris luctus, nulla ac blandit molestie, augue dui iaculis orci, eu suscipit ipsum mauris a enim. Curabitur vel mauris lorem. Maecenas et metus cursus, posuere nisi vitae, auctor turpi.
EOT;

$var = preg_replace('/[^\.]{2,}\.\s/', '$0[[SPLIT]]', $var);
$lines = explode('[[SPLIT]]', $var);

print_r($lines);

如果查看文本,可以构成以下逻辑:

  • 句子末尾的一个点应该始终跟空格:空格或换行符
  • 缩写后面还有空格。在许多情况下,虽然它只有一个字符。一个句子永远不会以一个字符结束(我认为),所以让我们说在该点之前必须有多个字符不是空格或点。

这个逻辑允许以下正则表达式:

/[^\.]{2,}\.\s/

正如您在此处所见,这有效:http://ideone.com/MkyEcL

请注意以下事项:

  • 您可以使用preg_split()执行此操作,但正如您在我的示例中所看到的,我尝试保持文本的正确性。所以我保留了积分,空白和换行符。我不知道如何用preg_split做到这一点,所以我把preg_replace()和explode()结合起来。
  • 另请注意,我可以想到我认为你无法捕获的案例。例如,以下句子:

    “我是Theman先生,我喜欢StackOverflow。”

    在这种情况下,缩写有多个字符,后跟空格,甚至是点后的字符,空格是大写字符。我认为在正则表达式中捕获此类案例根本不可能,因为您只需要知道它是否是缩写。

答案 4 :(得分:-1)

尝试$str = preg_replace("/[\.](+[0-9])/", "$1", $str);