2011-03-29 80 views
1

我有一個(php5.2和5.3)正則表達式,需要從用戶帖子(可能包括電子郵件地址和超鏈接)中提取第一個$ x句子,並且無法找出原因是的,這是一個醜陋的正則表達式,我將優化它時,它的工作原理):PHP preg_match組重複

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

返回前四句,但

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

沒有返回比賽。我的理解是{0,5}應該與之前的組匹配0到5次,並且如果它只能匹配4次,它應該仍然有效。

任何人都可以闡明這種行爲?

更新:$ x只是一個任意數字;在正則表達式中使用{0,$ x}。帖子被過濾爲由單個空格分隔的句子。對不起,這個醜陋的表情......已經看了幾天,現在正在我的腦海中......做出了由sawa建議的更改。我的主要問題是關於行爲,小組匹配的內容不應該太重要。

UPDATE2:這基本上是我在做什麼:

function extractSummary($message, $limit) { 
    $expr = '/^(([^.!?]+|(\w+[[email protected]?&=%:])+\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領土,COS站點它只是一個函數)是什麼都漲到句點,感嘆號或問號,但時段可以出現在URL的電子郵件地址的句子中。這個正則表達式的最後一個版本只計算了5個時間段,因此打破了鏈接和電子郵件地址。

更新3:回想一下,我剛剛添加了更可怕的代碼,我會解釋最後一個。發現某些發佈的內容具有非打印字符(如\ r等),但與正則表達式無法很好地配合使用,所以我刪除了第一個preg_replace的非打印字符。第二個用一個空格代替任何進一步的空白組,所以這些句子有希望被一個空格分開。

+0

什麼是$ x句子?帖子是怎麼樣的? – sidyll 2011-03-29 01:36:41

+0

在這之前,你應該清理你的正則表達式。例如,你不需要最外面的一對圓括號' ((\ w + [.... \ w)'),並且你對捕獲不一致:有時你有'(...)',而有時候你有'(?:...)'。只有當你想提取那部分時,我認爲發佈一個複雜的正則表達式並且讓人們遵循它是不禮貌的 – sawa 2011-03-29 01:39:29

+0

謝謝你的建議,但我認爲一些例子句是必要的,或者至少你應該告訴我們你認爲這是一個句子,句子只是一段時間的序列嗎?從你所擁有的東西推測出來,這可能不是這種情況。句子只有在它是電子郵件地址的一部分時才允許在句子中使用?什麼 是定義一個句子的條件? – sawa 2011-03-29 02:01:31

回答

0

我識別句子如下所示:

一個句子是:

  • 的最短序列到一個週期,感嘆號,或問號,
  • 任選接着通過單引號或雙引號,
  • 強制性後跟空格或字符串的結尾。

由於電子郵件地址中的句點沒有出現在空格之前或字符串末尾,因此空格或字符串結尾的此要求會在電子郵件地址中處理時段。

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

即使在基本情況下,這也不會導致匹配。嘗試使用「這是一個句子,這是句子2.這個句子有一個[email protected],它有一個鏈接http://somewhere.com。這句話不應該出現在輸出中。」 – Rodney 2011-03-29 02:28:26

+0

是的,都嘗試過。更新之前,結果不是不匹配,但匹配是空字符串。這從正則表達式中是有意義的,但不是我所追求的 - 我需要提取句子,而不是測試比賽。 – Rodney 2011-03-29 02:31:29

+0

僅提取第一句。稍作修改後,會得到前4個句子:「/(.*?[!!?](?=\s)){0,4}/」,但遇到電子郵件地址或鏈接時仍會中斷。 – Rodney 2011-03-29 02:49:23

0

正則表達式無條件地匹配空白字符。如果輸入中只有5個句子,上一個句號後沒有空格,則第一個匹配,而第二個不匹配。

+0

這並不能解釋爲什麼它在第一個正則表達式中成功,而在第二個正則表達式中失敗,正如羅德尼所說的那樣。 – sawa 2011-03-29 02:10:06

+0

在通過正則表達式運行之前,該文章末尾插入了一個空格,以避免這種可能性。 – Rodney 2011-03-29 02:11:41

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." or "This one!"或'This one'?

+0

不錯,但是在帶有鏈接的句子之前停止輸出:例如「這是句子一,這是兩個,這是[email protected]三。」只有輸出「這是一句話,這是兩個。」即使$ x> 2。 – Rodney 2011-03-29 02:55:03

+0

@Rodney:不會的。它對你的例子很好用,結尾標點符號後面必須有空格或行尾。 – ridgerunner 2011-03-29 03:00:01

+0

我的不好,錯誤地輸入了你的表情。效果很好。感謝堆! – Rodney 2011-03-29 03:06:16