优化句子消毒剂的正则表达式

时间:2012-11-18 21:33:39

标签: php regex preg-replace

这是一个句子清洁剂。

function sanitize_sentence($string) {
    $pats = array(
    '/([.!?]\s{2}),/',      # Abc.  ,Def
    '/\.+(,)/',             # ......,
    '/(!|\?)\1+/',          # abc!!!!!!!!, abc?????????
    '/\s+(,)/',             # abc   , def
    '/([a-zA-Z])\1\1/');    # greeeeeeen
    $fixed = preg_replace($pats,'$1',$string); # apply pats
    $fixed = preg_replace('/(?:(?<=\s)|^)[^a-z0-9]+(?:(?=\s)|$)/i', '',$fixed); # bad chunks
    $fixed = preg_replace( '/([!?,.])(\S)/', '$1 $2', $fixed); # spaces after punctuation, if it doesn't exist already
    $fixed = preg_replace( '/[^a-zA-Z0-9!?.]+$/', '.', $fixed); # end of string must end in period
    $fixed = preg_replace('/,(?!\s)/',', ',$fixed); # spaces after commas
    return $fixed;
}

这是测试句:

  

你好[[[[[[]]]]]]朋友.....?你好吗[}}}}}}

它应该返回:

  你好朋友.....?你好吗

但它正在回归:

  你好朋友。 .. ..?你好吗。

所以有2个问题,我无法找到解决方案:

  1. 这些时期被分成&#34; .. ..&#34;由于某些原因。他们应该保持为&#34; .....&#34;问号旁边。
  2. 如果字符串中的任何字符中至少有一个字符,那么字符串的结尾必须只在的句点结束,并且只有!?,。(如果至少有一个字符在字符串中找不到,不应该执行preg_replace)
  3. 第二个问题的例子:

      

    这句话不需要结束时间,因为提到的字符无处可寻。

         

    这句话,需要它!为什么?因为它至少包含一个提到的字符

    (当然,只有在尚未存在的情况下才能放置结束期)

    感谢您的帮助!

1 个答案:

答案 0 :(得分:4)

以下是您第一个问题的答案。第三个到最后一个替换是问题:

$fixed = preg_replace( '/([!?,.])(\S)/', '$1 $2', $fixed); # spaces after punctuation, if it doesn't exist already

它将第一个句点与字符类匹配,第二个句点作为非空格字符。然后插入一个空格。由于匹配不能重叠,因此它将匹配第三个和第四个周期并插入空格,依此类推。这可能是最好的解决方法:

$fixed = preg_replace( '/[!?,.](?![!?,.\s])/', '$0 ', $fixed);

以下是您如何处理第二项要求(替换倒数第二位preg_replace):

$fixed = trim($fixed);
$fixed = preg_replace( '/[!?.,].*(?<![.!?])$/', '$0.', $fixed);

首先,我们摆脱前导和尾随空格,将此问题与尾随时期区分开来。然后preg_replace将尝试在字符串中找到标点符号,如果是,则匹配所有内容直到字符串结尾。替换将比赛放回原位并追加期限。注意负面的背后。它断言字符串不会以句尾标点符号结尾。