2010-11-30 3 views
2

Я использую cakephp 1.3, и у меня есть textarea, где пользователи отправляют статьи. В submit, я хочу заглянуть в статью для определенных ключевых слов и добавить соответствующие теги в статью.Любая более быстрая, простая альтернатива php preg_match

Я думал о preg_match, но шаблон preg_match должен быть строкой. Поэтому мне пришлось бы перебирать массив (большой).

Есть ли более простой способ подключить массив ключевых слов для шаблона.

Я ценю всю вашу помощь.

Спасибо.

ответ

3

Я предлагаю обработать ваш массив ключевых слов, как хэш-таблицу. Строчный текст статьи, взорваться пробелами, затем прокручивать каждое слово разнесенного массива. Если слово существует в вашей хеш-таблице, подталкивайте его к новому массиву, отслеживая количество раз, когда оно было замечено.

Я провел быстрый тест, сравнивающий регулярное выражение с хэш-таблицами в этом сценарии. Чтобы запустить его с регулярным выражением 1000 раз, потребовалось 17 секунд. Чтобы запустить его с хэш-таблицей 1000 раз, потребовалось 0,4 секунды. Это должен быть процесс O (n + m).

$keywords = array("computer", "dog", "sandwich"); 
$article = "This is a test using your computer when your dog is being a dog"; 
$arr = explode(" ", strtolower($article)); 
$tracker = array(); 

foreach($arr as $word){ 
    if(in_array($word, $keywords)){ 
     if(isset($tracker[$word])) 
      $tracker[$word]++; 
     else 
      $tracker[$word] = 1; 
    } 
} 

в $ массив трекер выведет: «компьютер» => 1, «собака» => 2. Вы можете сделать процесс, чтобы решить, какие теги использовать. Или, если вас не волнует количество раз, когда появляется ключевое слово, вы можете пропустить часть трекера и добавить теги по мере появления ключевых слов.

РЕДАКТИРОВАТЬ: Ключевое слово array может потребоваться преобразовать массив индексов, чтобы обеспечить быстрый поиск. Я не уверен, как работает in_array(), но если он ищет, то это не так быстро, как должно быть. Перевернутый массив индекса будет выглядеть

array("computer" => 1, "dog" => 1, "sandwich" => 1); // "1" can be any value 

Тогда вы могли бы сделать Исеть ($ ключевые слова [$ слово]), чтобы проверить, если слово соответствует ключевому слову, вместо in_array(), который должен дать вам O (1) , Тем не менее, кто-то еще сможет мне это разъяснить.

+0

за быстрый ответ. Он отлично работает, когда нет тэгов xhtml. Но у меня есть теги xhtml в статье. Есть ли способ обход этого. –

+0

Хм, тогда регулярное выражение не может быть полностью предотвращено. Вы можете применить strip_tags() к строке статьи перед тем, как опустить ее. Это должно заботиться обо всех тегах XHTML. Однако может быть небольшое влияние на скорость. – Nick

+0

Это почти то же самое, что я использовал с помощью array_count_values ​​() и str_word_count() .. :) @JoshR Вам нужно также снять теги XHTML? Потому что вы этого не говорили. – redShadow

0

strtr()

Если данных двух аргументов, то второй должен быть массив в массиве формы ('от' => 'до', ...). Значение return - это строка, в которой все вхождения ключей массива имеют , которые были заменены соответствующими значениями . Самые длинные ключи будут проверены сначала . Как только подстрока была заменена на , ее новое значение не будет равно .

+0

strtr приятно, но Джош не ищет замену, а ищет. –

+0

О, я думал, что он хочет заменить ключевые слова ссылками на тег или что-то в этом роде. – AndreKR

1

Если вам не нужна сила регулярных выражений, вы должны просто использовать strpos().

Вам все равно нужно будет прокрутить массив слов, но strpos намного, намного быстрее, чем preg_match.

0

Добавление тегов вручную? Точно так же, как мы добавляем теги здесь, в SO.

2

Конечно, вы можете попробовать совместить все ключевые слова, используя одно единственное регулярное выражение, например /word1|word2|word3/, но я не уверен, что это то, что вы ищете. А также я думаю, что это будет довольно тяжело и ресурсоемким.

Вместо этого вы можете попробовать с другим подходом, например, разделить текст на слова и проверить, интересны ли слова или нет. Я хотел бы сделать использование str_word_count() использованием как коснуться:

$text = 'this is my string containing some words, some of the words in this string are duplicated, some others are not.'; 
$words_freq = array_count_values(str_word_count($text, 1)); 

, который разделяет текст на слова и рассчитывает вхождения. Затем вы можете проверить с помощью in_array($keyword, $words_freq) или array_intersect(array_keys($words_freq), $my_keywords).

Если вам неинтересно, как я полагаю, к делу ключевых слов, вы можете strtolower() весь текст перед тем, как продолжить расщепление слов.

Конечно, единственный способ определить, какой из подходов лучше всего - это настроить некоторые тесты, запустив различные функции поиска против некоторого «репрезентативного» и довольно длинного текста и измеряя время выполнения и использование ресурсов (попробуйте microtime(TRUE) и memory_get_peak_usage() для сравнения).

EDIT: Я очистил немного коды и добавил недостающую запятую :)

2

Если вы хотите посмотреть на несколько слов из массива, а затем объединить указанный массив в регулярное выражение:

$regex_array = implode("|", array_map("preg_escape", $array)); 
preg_match_all("/($regex_array)/", $src, $tags); 

Это преобразует ваш массив в /(word|word|word|word|word|...)/. Параметр arrray_map и preg_escape необязателен, необходим только в том случае, если массив $ может содержать.

Избегайте strpos и петель для этого случая. preg_match быстрее для поиска по альтернативам.

+0

+1 для использования preg_escape(), что большинство людей игнорирует – redShadow

Смежные вопросы