2

这是一个句子消毒剂。

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;
}

这是测试语句:

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

它应该返回:

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

但相反,它正在返回:

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

所以有两个问题,我找不到解决方案:

  1. 这组时期被分成“.. .. .” 由于某些原因。它们应该在问号旁边保留为“.....”。
  2. 字符串的结尾必须仅以句点结尾,并且仅当字符串中的任何位置至少存在以下字符之一时:!?,。(如果在字符串中找不到这些字符中的至少一个,则不应执行 preg_replace)

第二个问题的例子:

这句话不需要结束句号,因为找不到提到的字符

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

(当然,结束期只有在不存在的情况下才应该放置)

谢谢你的帮助!

4

1 回答 1

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将尝试在字符串中找到标点符号,如果找到,它将匹配所有内容,直到字符串结尾。替换将匹配放回原处并附加句点。注意消极的后视。它断言该字符串尚未以句子结尾的标点符号结尾。

于 2012-11-18T21:40:43.540 回答