2009-12-22 195 views
0

我有這個網頁,用戶可以添加表情符號到他們的意見。我想限制每條評論的表情符號數量。該「系統」的作品,但我有一些問題,正則表達式的一部分。 我有一個配置文件中定義我的表情就像這樣:匹配文本字符串

$config['Smilies'] = Array (
    // irrelevant stuff 
    'smilies' => Array (
     ':)' => 'smile.gif', 
     ':(' => 'sad.gif', 
     // some more smilies 
     's:10' => 'worship.gif', 
     's:11' => 'zip.gif', 
     's:12' => 'heart.gif', 
     // some more smilies 
     's:1' => 'dry.gif', 
     's:2' => 'lol.gif', 
     's:3' => 'lollol.gif', 
     // some more smilies 
    ) 
); 

,然後當我驗證評論(看看有多少笑臉在那裏),我環槽這個陣列和微笑匹配的內容評論。正則表達式中使用這樣的:

foreach ($this->config['smilies'] as $smilie => $smilieImage) 
{ 
    $matches = Array(); 
    Preg_Match_All ('/' . Preg_Quote ($smilie) . '/i', $Content, $matches); 

    $numOfFoundSmilies += Count ($matches[0]); 
} 

的問題是了,如果我輸入「S:10」到註釋,上面的代碼會發現兩個匹配:「S:10」和「S: 1" 。我的正則表達式的知識是非常差的,我不明白這一個。

+1

也許你應該改變s:1到s:01等。 – Artelius 2009-12-22 09:17:31

回答

3

正則表達式是greedy默認情況下(至少PCREs)。通常,你可以繞過這個:

/a+/ # selects the whiole string from "aaaaaaa" 

/a+?/ # selects only "a" 

在你的情況,這沒有太大的幫助,因爲你不能只是一個問號扔的地方。唯一的可能性是重排序搜索陣列,並立即更換發現的地方。搜索第一個s:10第二個s:1,並使用preg_replace()代替匹配。這樣,第二個不會再找到第一個。

另一種可能性:一分爲二的搜索陣列。如果你知道,那一個總是具有結構的:「加數字,你可以有你的正則表達式在本次循環像

Preg_Match_All ('/' . Preg_Quote ($smilie) . '(?![0-9])/i', $Content, $matches); 

(?![0-9])一個look ahead expression尋找任何位數字。

而第三個:如果允許(==轉換),在某些地方只有表情,你可以這樣做:

Preg_Match_All ('/\b' . Preg_Quote ($smilie) . '\b/i', $Content, $matches); 

\b是一個「單詞邊界」,通常任何不可─(字母,數字,下劃線)。顯然缺點是,並不是所有的表情符號(如「abc ;-) xyz」)都會被找到。

+0

我不認爲這會起作用,因爲他爲每個笑臉開始一個新的正則表達式搜索。像Fortega說的 – Fortega 2009-12-22 09:20:53

+0

,這對我不起作用。它可以,如果我會盡快替換找到的微笑,但我必須先驗證,然後將文本表情符號轉換爲圖像,如果驗證通過的話...... – 2009-12-22 09:23:43

+0

但是,如果替換是由第一個正則表達式,那麼第二個正則表達式不會找到s:1。 +1 – 2009-12-22 09:23:57

4

對於每個微笑代碼,您的代碼會計算出該代碼在帖子中出現的次數,所以:10'都計爲'10'和':1'。

一個解決方案是一次查找所有的笑容代碼,以便每篇文章只計算一個笑臉代碼。這可以通過將所有代碼合併爲一個正則表達式來完成。

$codes = array_keys($smilie); 
$escCodes = array_map('preg_quote', $codes); 
$regex = '/'.implode('|',$escCodes).'/i'; 

preg_match_all($regex, $Content, $matches); 

$found = count($matches); 
+0

這也適用,但我去了Boldewyn的解決方案,因爲它需要更少的代碼更改。謝謝! – 2009-12-22 09:34:33

+0

是的,着名的'或'表達。 +1,我忘了這個簡單的。 – Boldewyn 2009-12-22 09:40:01

0

你可以改變你使用regexen使用word boundaries或用\ s(空格)來匹配,所以s:1成爲\bs:1\b\ss:1\s。請注意,第二種方法s:1.將不匹配,並且兩個版本都不匹配This is my funny texts:1

0

將「s:1」更改爲「s:1 [^ 0-9]」 - 匹配任何「s:1」,後面跟着另一個數字。

+0

但是,當它出現在字符串的最後時,它不會匹配「s:1」。你的正則表達式_requires_之後的另一個字符。在這種情況下,負向預測會更好:'s:1(?![0-9])'。 – Geert 2009-12-22 17:23:17

1

我想像這個代碼是快於正則表達式

$replaced = str_replace(array_keys($config['Smilies']), 
         array_values($config['Smilies']), 
         $message, $count); 

這不會與s:1s:10解決問題的,所以我建議使用一個更明確的分隔符/邊界符號這,例如:s10:而不是s:10。那麼它就不再是一個問題了。

另外,我建議不要爲此使用數字標識符。用戶可能會覺得記住它們很乏味。爲什麼不使用容易記憶的標籤,例如:heart::lol:

+0

+1爲人類可讀標籤 – 2009-12-22 11:55:05

+0

我有一些表情符號上的人類可讀標籤,但我只是不能拿出30個表情符號的標籤... – 2009-12-22 12:49:47