PHP preg_match组重复

时间:2011-03-29 01:30:15

标签: php regex preg-match

我有一个(php5.2和5.3)正则表达式需要从用户帖子中提取前$ x个句子(可能包括电子邮件地址和超链接),并且我在查找原因时遇到了麻烦(是的,它& #39;是一个丑陋的正则表达式;当它工作时我会优化它):

/^(([^.!?]+|(\w+[.@?&=%:])+\w+)+[.!?]+\s){0,4}/

返回前四个句子,但是

/^(([^.!?]+|(\w+[.@?&=%:])+\w+)+[.!?]+\s){0,5}/

不返回任何匹配项。我的理解是{0,5}应该与之前的组匹配0到5次,因此如果它只能匹配4次,它仍然可以工作。

任何人都可以对这种行为有所了解吗?

更新:$ x只是一个任意数字;在正则表达式中使用{0,$ x}。将帖子过滤为由单个空格分隔的句子。对于这个丑陋的表情感到抱歉......现在已经对这个问题进行了几天的调查,并且它正在努力......做出了sawa建议的改变。我的主要问题是关于行为,而小组匹配的内容不应该那么重要。

Update2:这基本上就是我正在做的事情:

function extractSummary($message, $limit) {
  $expr = '/^(([^.!?]+|(\w+[.@?&=%:])+\w+)+[.!?]+\s){0,'.$limit.'}/';
  $msg = preg_replace('/[\x00-\x1f\x80-\xff]/', "\n" strip_tags($message));
  $msg = trim(preg_replace('/(\n|\s| )+/', ' ', $msg)).' ';
  preg_match($expr, $msg, $summary);
  return $summary[0];
}

一句话(至少在我的脑海里,没有进入NLP领域,因为它只是网站中的一个功能)是一个句号,感叹号或问号,但句子可以出现在句子中网址的电子邮件地址。这个正则表达式的最后一个版本最多可以计算5个周期,因此会破坏链接和电子邮件地址。

更新3:重申我刚刚添加了更多可怕的代码,我将解释最后一个。发现一些发布的内容有非打印字符(如\ r等),并且与正则表达式不能很好地协作,因此我使用第一个preg_replace删除了非打印字符。第二个用空格替换任何进一步的空格组,所以句子有希望用一个空格分隔。

3 个答案:

答案 0 :(得分:0)

正则表达式通过无条件匹配空白字符而结束。如果输入中恰好有5个句子,并且在最后一个句点之后没有空格,则第一个句子匹配,但第二个句子不匹配。

答案 1 :(得分:0)

我认为句子如下:

一句话是:

  • 最短的序列,包括句号,感叹号或问号,
  • 可选地后跟单引号或双引号,
  • 强制性地跟着一个空格或字符串的结尾。

空格或字符串结尾的要求会处理电子邮件地址中的句点,因为电子邮件地址中的句点不会出现在空格之前或字符串末尾。

/[^ ](?:.*?[.!?]['"]*(?= |\z)){0,4}/

答案 2 :(得分:0)

这个测试过的功能应该可以解决问题:

function get_sentences($text, $x) {
    $regex = "/\A(?:.*?[\w\"'][.?!](?=['\"]?\s|\$)){0,{$x}}/ms";
    if (preg_match($regex, $text, $matches)) return $matches[0];
    return ''; // Never get here (will always match).
}

以下是正则表达式的注释版本:

$regex = '/# Match first $x sentences, each ending in [.?!]
    \A                # Anchor to beginning of string
    (?:               # Non-capture group to apply count
      .*?             # Lazily match zero or more characters.
      [\w"\']         # Last char before end is word or quote.
      [.?!]           # End of sentence puntuation [.?!]
      (?=[\'"]?\s|$)  # But only if followed by space or EOL
    ){0,5}            # Match from zero to $x sentences.
    /smx';

请注意,这也处理以引号结尾的句子,例如: "This one.""This one!"或“这一个”?