2014-06-10 91 views
0

我有以下代碼:PHP檢查字符串中的字符,而不foreach循環

$wordsArray = ... 
foreach ($wordsArray as $word) 

    if (strpos($string, $word) !== FALSE) { 
     echo "Word found! Handle this a certain way" } 
    } 

} 

不幸的是,這樣一個大陣的話(可能接近100),環太慢尤其是當我傳遞了數千個字符串到這個函數,並且運行這個foreach循環幾千次。我怎樣才能加快這個過程,或者重構我的代碼,這樣我就不需要遍歷我的數組了,而是使用字符串本身並檢查它的任何子字符串是否在我的數組中找到?我需要使我的代碼的這部分更有效率。

此外,是什麼讓這更困難的是,每個字符串沒有空格。相反,採取下面的例子:

傳遞的字符串: 「Hereissomerandomsentence」 詞

陣列:( '一些', '是', '的');

我的腳本會返回Word,因爲「一些」,但我想找到一個更快的方式來做到這一點。

+0

「不需要遍歷我的數組字符,而是使用字符串本身,並檢查是否在我的數組中找到它的任何子字符串」---爲什麼你認爲'2 + 3'是快於「3 + 2」? – zerkms

+0

可悲的事實是,使用foreach和in_array比使用聲明或匿名函數的array_walk快。你到底在做什麼?試圖找到壞詞? – Ohgodwhy

+0

這個問題似乎是離題,因爲它是關於改善工作代碼,並可能更適合http://CodeReview.stackexchange.com/ –

回答

1

簡單但也不容易。下面是使用preg_match_all和簡單的正則表達式作爲一個例子一些代碼:

// Set the string. 
$string = 'Hereissomerandomsentence'; 

// Set the words array. 
$wordsArray = array('some', 'are', 'the'); 

// Set the regex pattern. 
$regex_pattern = '/(?:' . implode('|', $wordsArray) . ')/i'; 

// Run a regex to get the value between the link tags. 
preg_match_all($regex_pattern, $string, $matches); 

// Return the results. 
echo '<pre>'; 
print_r($matches); 
echo '</pre>'; 

,這裏是結果:

Array 
(
    [0] => Array 
     (
      [0] => some 
     ) 

) 

但是,當我說這是不容易的,缺乏的空間,可能會導致thenthe等匹配。請記住,電腦無法閱讀。這都是模式邏輯。所以,如果我添加thenare的例子字符串是這樣的:

// Set the string. 
$string = 'Hereissomerandomsentencethenhereweare'; 

結果反映thenthe被拾起:

Array 
(
    [0] => Array 
     (
      [0] => some 
      [1] => the 
      [2] => are 
     ) 

) 

編輯:樓主問了一個fair-但在評論中的複雜問題:

如果我只想要一個單詞前面有一個單詞還是某個單詞?對於 例如,使用相同的測試字符串,你怎麼能夠改變正則表達式 通過 then前面時isthe時之前只包括some,並通過are「我們」先當?因此,對於您的示例, 輸出將僅爲'some'和are

你所要求做的是複雜的,但可行使用「Lookarounds」 as explained on this site

下面是一個使用上面的代碼示例:

$string = 'Hereissomerandomsentencethenhereweare'; 

// Set the regex pattern. 
$regex_pattern = '/(?<=is)some|(?<=then)the|(?<=we)are/i'; 

// Run a regex to get the value between the link tags. 
preg_match_all($regex_pattern, $string, $matches); 

// Return the results. 
echo '<pre>'; 
print_r($matches); 
echo '</pre>'; 

,其結果將是爲你期望它:

Array 
(
    [0] => Array 
     (
      [0] => some 
      [1] => are 
     ) 

) 

這裏是該正則表達式的說明/(?<=is)some|(?<=then)the|(?<=we)are/i

  • 開頭和結尾的斜線(/)只是分隔符。
  • |字符是簡單的和OR之間的條件。
  • 現在在OR條件之間是什麼樣的模式。

現在讓我們以第一個(?<=is)some爲例。

  • (?<=[word in here])是一個「Lookbehind」,意思是:只有在這個詞前面有這個單詞時,纔會捕獲這個單詞。在這種情況下的字是is
  • 下面的單詞是some
  • 所以這一切都增加到:只匹配some如果前面有is。然後the只有前面有then。然後are只有前面有we

現在知道這裏有一個模式可能可能會創建一個多維數組,它可以爲單詞設置邏輯,以便僅在被另一個單詞前面檢查時檢查。然後循環創建一堆正則表達式。但這是一項重大任務。

但至少現在你知道這個任務的正則表達式的基本知識!

+0

但是這裏的問題是性能,而不是代碼本身的質量。你能在這裏提供一些基準嗎? – Ohgodwhy

+0

@Ohgodwhy「你能在這裏提供一些基準嗎?」不是。爲什麼?原始海報想要做的概念將如所呈現的那樣成爲資源消耗。而設計一個更快的解決方案意味着重構這裏沒有提供的代碼。 – JakeGould

+0

這很酷!但爲什麼它會輸出每個匹配數組兩次?我有點困惑。感謝你! @JakeGould – user3692430

2

會有一些環路參與,不管你喜歡還是不喜歡,但是當你切換到正則表達式,而不是一些優化可能是可行的:

$re = '/(?:' . join('|', array_map(function($word) { 
    return preg_quote($word, '/'); 
}, $wordsArray)) . ')/'; 

if (preg_match_all($re, $string, $matches)) { 
    // hurray! 
    print_r($matches[0]); 
} 
+0

「選擇的表達式使用'\ b'(單詞邊界)斷言來確保(在某種程度上)它只匹配整個單詞。」這與原始海報詢問關於字符串的內容沒有像'這裏有一些隨機的句子「,」而且,更麻煩的是每個字符串都沒有空格。「這絕對不行。 – JakeGould

+1

@JakeGould不知何故,我明白了與之相反的:)更新。 –

1
  • 排序保存潛在的下屬字陣列可以在$ string中找到 。
  • 考慮一個由起始字母組織的多維數組;製作一個潛在的匹配字典,而不是使用一個巨大的,未排序的數組。
  • 將$ string的副本剪切成單個字符,解析它。
  • 知道在哪個索引處可以找到哪些字符。
  • 將這些字符放入一個集合中,以便您只使用唯一的 字符。
  • 檢查每個獨特的字符。如果 陣列中的從屬單詞不以這些唯一字符之一開頭,或者保留這些字符,則可以將其作爲潛在匹配丟棄。

使用這樣的想法,可以減少所需的比較次數。通過減小潛在解決方案的大小,您可能可以加快匹配速度。

爲了讓這些縮減技術顯示出它們的價值,潛在的匹配數組需要很大。也就是說,您節省的處理時間將需要超過處理時間花費在切除不太可能的匹配上。

在所提供的樣本串,字母表中使用這樣的: b 的C 1 d 1 Ë11 ˚F 克 H 3 I 1 Ĵ ķ 升 米2 N 4 O 2 p q ,R 4 第3 噸2 ù v 瓦特1 x y z。

所以,根本沒有使用26個13個字母。有一半的信件沒有發生。另外,e的出現幾乎是其較接近的競爭對手的3倍:h,n和r。這意味着消除他們如何開始下屬的話可能會減少時間。