Модераторы: Aliance, skyboy, MoLeX, ksnk

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Регулярка для поиска нескольких слов 
:(
    Опции темы
KgCoder
Дата 12.7.2009, 19:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 93
Регистрация: 6.3.2008
Где: KGstan

Репутация: нет
Всего: нет



Уже третий день курю ману по регулярке. :(
Помогите решить. Есть данные:
Код

$text = 'Река Каракол начинается далеко в горах. Основная часть реки протекает в ущелье Каракол,' .
  ' где замедляется и через несколько километров проходит через город Каракол.';
$tags = array(
  ...
  5 => 'река Каракол',
  7 => 'город Каракол',
  21 => 'ущелье Каракол',
  ...
);


Как заменить все встречающиеся элементы из перменной $tag, чтобы текст после обработки был таким:
Код

$output= '<a href="tag/TAG[ID]">Река Каракол</a> начинается далеко в горах.' .
  ' Основная часть реки протекает в <a href="tag/TAG[ID]">ущелье Каракол</a>' .
  ', где замедляется и через несколько километров проходит через <a href="tag/TAG[ID]">город Каракол</a>.';


Это сообщение отредактировал(а) KgCoder - 12.7.2009, 21:24
PM MAIL   Вверх
enof
Дата 12.7.2009, 19:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 837
Регистрация: 23.1.2009
Где: Санкт-Петербург

Репутация: 1
Всего: 35



Код

foreach($tags as $id=>$tag)
    $text = preg_replace('#('.preg_quote($tag, '#').')#iu', '<a href="tag/TAG['.$id.']">$1</a>', $text);

PM MAIL ICQ Skype   Вверх
ksnk
Дата 12.7.2009, 20:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


прохожий
****


Профиль
Группа: Комодератор
Сообщений: 6855
Регистрация: 13.4.2007
Где: СПб

Репутация: 12
Всего: 386



Код

$text = 'Река Каракол начинается далеко в горах. Основная часть реки протекает в ущелье Каракол,' .
  ' где замедляется и через несколько километров проходит через город Каракол.';
$tags = array(
  5 => 'река Каракол',
  7 => 'город Каракол',
  21 => 'ущелье Каракол',
);
$GLOBALS['tags']=&$tags;
$reg=array();
// create regs
foreach($tags as $v){
  $reg[]=preg_replace('/\s+/si','\\s+',preg_quote($v));
}

//apply reg
echo preg_replace_callback('/('.implode(')|(',$reg).')/si',create_function('$matches','
    global $tags;
    $i=1;
    foreach($tags as $k=>$v){
        if(!empty($matches[$i])){
             return sprintf(\'<a href="tag/TAG%s">%s</a>\',$k,$v);
        }
        $i++;
    }
    return $matches[0];
'),$text);



--------------------
Человеку свойственно ошибаться, программисту свойственно ошибаться профессионально ! user posted image
PM MAIL WWW Skype   Вверх
KgCoder
Дата 12.7.2009, 21:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 93
Регистрация: 6.3.2008
Где: KGstan

Репутация: нет
Всего: нет



При добавлении в массив $tags элемента:
Код

  ...
  1 => 'Каракол',
  ...

Теги повторно оборачиваются :(
PM MAIL   Вверх
ksnk
Дата 12.7.2009, 22:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


прохожий
****


Профиль
Группа: Комодератор
Сообщений: 6855
Регистрация: 13.4.2007
Где: СПб

Репутация: 12
Всего: 386



KgCoder, в моем примере тоже?


--------------------
Человеку свойственно ошибаться, программисту свойственно ошибаться профессионально ! user posted image
PM MAIL WWW Skype   Вверх
enof
Дата 12.7.2009, 22:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 837
Регистрация: 23.1.2009
Где: Санкт-Петербург

Репутация: 1
Всего: 35



Цитата(ksnk @  12.7.2009,  21:36 Найти цитируемый пост)
preg_replace('/\s+/si','\\s+',preg_quote($v));

 smile 
PM MAIL ICQ Skype   Вверх
ksnk
Дата 12.7.2009, 23:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


прохожий
****


Профиль
Группа: Комодератор
Сообщений: 6855
Регистрация: 13.4.2007
Где: СПб

Репутация: 12
Всего: 386



enof, O! 777 сообшений - нужно отметить! smile

Это про что смайлик? 
Я там, типо, защищаюсь от нескольких пробелов в tags и в эталонном тексте. что-то не так?


--------------------
Человеку свойственно ошибаться, программисту свойственно ошибаться профессионально ! user posted image
PM MAIL WWW Skype   Вверх
enof
Дата 12.7.2009, 23:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 837
Регистрация: 23.1.2009
Где: Санкт-Петербург

Репутация: 1
Всего: 35



Не могу понять, что такое "\\s+" в replacement и зачем юзать preg_quote для subject.
Цитата(ksnk @  13.7.2009,  00:08 Найти цитируемый пост)
O! 777 сообшений - нужно отметить! smile

 smile 
PM MAIL ICQ Skype   Вверх
ksnk
Дата 12.7.2009, 23:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


прохожий
****


Профиль
Группа: Комодератор
Сообщений: 6855
Регистрация: 13.4.2007
Где: СПб

Репутация: 12
Всего: 386



enof, 
К примеру
Код

$tags=array(...
4=>'Где ты  Бетмен?', // 2 пробела случайно поставлено перед Бетмен
...
);
  preg_replace('/\s+/si','\\s+',preg_quote($v));
...
 выдаст чего-то наподобии 
Код

Где\s+ты\s+Бетмен\?
? что в общем-то примерно то, что и нужно было бы искать топикстартеру...
В принципе, два слеша не очень то и нужны, с одним тоже работает...



--------------------
Человеку свойственно ошибаться, программисту свойственно ошибаться профессионально ! user posted image
PM MAIL WWW Skype   Вверх
enof
Дата 12.7.2009, 23:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 837
Регистрация: 23.1.2009
Где: Санкт-Петербург

Репутация: 1
Всего: 35



ааа, все ясно, затупил чет smile 
PM MAIL ICQ Skype   Вверх
KgCoder
Дата 13.7.2009, 05:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 93
Регистрация: 6.3.2008
Где: KGstan

Репутация: нет
Всего: нет



Эхм, спасибо. Сейчас пересядю на PC и попробую. И еще один вопрос. Если скажем элементов в массиве $tag будет > 500, система не нагрузиться? В принципе у меня есть кеширование, но всё-же не хотелось бы получить timeout из-за регулярок.
PM MAIL   Вверх
KgCoder
Дата 13.7.2009, 07:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 93
Регистрация: 6.3.2008
Где: KGstan

Репутация: нет
Всего: нет



В общем потестил. Выложу полный код (Drupal):
Код

    ...
    $result = db_query($query);
    while ($term = db_fetch_object($result)) {
      $glossary_term[$term->tid] = $term->name;
    }
    $GLOBALS['glossary_term'] = &$glossary_term;
    $reg = array();
    foreach($glossary_term as $v) {
      $reg[]=preg_replace('/\s+/si','\\s+',preg_quote($v));
    }
    $node->body = preg_replace_callback('/('.implode(')|(',$reg).')/si', create_function('$matches', '
      global $glossary_term;
      $i = 1;
      foreach($glossary_term as $k => $v) {
        if(!empty($matches[$i])){
          return sprintf(\'<span class="advanced-glossary-term info-tip" id="term-%d">%s</span>\', $k, $v);
        }
        $i++;
      }
      return $matches[0];
    '), $node->body);
    ...

Теги в массиве: Karakol river, Karakol peak, Karakol city, Karakol
Результат обработки: Karakol river, goes near Karakol peak and enters Karakol city. Once more Karakol

Сделал так:
Код

    ...
    $result = db_query($query);
    while ($term = db_fetch_object($result)) {
      $glossary_term[$term->tid] = $term->name;
    }
    foreach ($glossary_term as $tid => $term) {
      $pattern = '/\b(?<!\"|\/)' . $term . '\b/';
      $replacement = '<span class="advanced-glossary-term info-tip" id="term-' . $tid . '">' . $term . '</span>';
      if (variable_get('advanced_glossary_teaser', TRUE)) {
        $node->teaser = preg_replace($pattern, $replacement, $node->teaser,
          variable_get('advanced_glossary_link_first_only', true) ? 1 : -1);
      }
      $node->body = preg_replace($pattern, $replacement, $node->body,
        variable_get('advanced_glossary_link_first_only', true) ? 1 : -1);
    }
    ...

Теги в массиве: Karakol river, Karakol peak, Karakol city, Karakol
Результат: Karakol river, goes near Karakol peak and enters Karakol city. Once more Karakol

Желаемый результат: Karakol river, goes near Karakol peak and enters Karakol city. Once more Karakol
Если сказать короче, то каждый тег должен выделиться в тексте. Сейчас пытаюсь искать в модулях типа wiki, glossary, а также сторонних скриптах.

Добавлено через 4 минуты и 14 секунд
ksnk, enof, спасибо, что откликнулись. При завершении модуля, укажу вас в списке хороших людей на drupal.org. Мелочь а приятно. smile

Это сообщение отредактировал(а) KgCoder - 13.7.2009, 07:25
PM MAIL   Вверх
ksnk
Дата 13.7.2009, 08:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


прохожий
****


Профиль
Группа: Комодератор
Сообщений: 6855
Регистрация: 13.4.2007
Где: СПб

Репутация: 12
Всего: 386



Цитата(KgCoder @  13.7.2009,  07:24 Найти цитируемый пост)
Желаемый результат...
Нужно отсортировать теги в массиве так, чтобы Karakol шел после Karakol river

Насчет эффективности - тут надо тестировать, но чем больше регулярка, тем она медленее "работает", так что 500 элементов - это, наверное, многовато...

Вообще-то можно заменить все найденные теги по методу  enof, но не на конечный "ссылочный" тег, а на какой-нибудь закорюк - @TAG[ID]@, к примеру. После полной замены всех тегов, поменять все закорюки на нужные ссылки, вторым "проходом" по массиву


--------------------
Человеку свойственно ошибаться, программисту свойственно ошибаться профессионально ! user posted image
PM MAIL WWW Skype   Вверх
KgCoder
Дата 13.7.2009, 10:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 93
Регистрация: 6.3.2008
Где: KGstan

Репутация: нет
Всего: нет



ksnk, При сортировке и использовании моего варианта будет работать? Я тут подумал над сортировкой. Кажется придётся при добавлении записей БД делать strlen и вставлять её как еще один параметр :( Или я усложняю?
PM MAIL   Вверх
KgCoder
Дата 13.7.2009, 11:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 93
Регистрация: 6.3.2008
Где: KGstan

Репутация: нет
Всего: нет



Сделал сортировку. Использую мой регулярку.
Результат: Karakol river, goes near Karakol peak and enters Karakol city. Once more Karakol
Тег Каракол будучи последним втискивается в уже отмеченный Karakol river. :(

Это сообщение отредактировал(а) KgCoder - 13.7.2009, 11:07
PM MAIL   Вверх
ksnk
Дата 13.7.2009, 11:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


прохожий
****


Профиль
Группа: Комодератор
Сообщений: 6855
Регистрация: 13.4.2007
Где: СПб

Репутация: 12
Всего: 386



сортировка массива по длине значения...
Код

$tags = array(
  5 => 'река Каракол',
  7 => 'город Каракол',
  21 => 'ущелье Каракол',
  1=>'Каракол',
);

uasort($tags,create_function('&$a,&$b','
   if (strlen($a) == strlen($b)) return 0;
   return (strlen($a) > strlen($b)) ? -1 : 1;
'));
var_dump($tags);




--------------------
Человеку свойственно ошибаться, программисту свойственно ошибаться профессионально ! user posted image
PM MAIL WWW Skype   Вверх
KgCoder
Дата 13.7.2009, 11:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 93
Регистрация: 6.3.2008
Где: KGstan

Репутация: нет
Всего: нет



Цитата(ksnk @  13.7.2009,  11:14 Найти цитируемый пост)
сортировка массива по длине значения...

Уже отсортировал, но спасибо. Не могли бы вы еще подсказать, что делать с этим: 
Цитата(KgCoder @  13.7.2009,  11:06 Найти цитируемый пост)
Сделал сортировку. Использую мой регулярку.
Результат: Karakol river, goes near Karakol peak and enters Karakol city. Once more Karakol
Тег Каракол будучи последним втискивается в уже отмеченный Karakol river. :(



Это сообщение отредактировал(а) KgCoder - 13.7.2009, 11:25
PM MAIL   Вверх
enof
Дата 13.7.2009, 11:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 837
Регистрация: 23.1.2009
Где: Санкт-Петербург

Репутация: 1
Всего: 35



Можно проверить, есть ли перед или после слова открывающий и закрывающий теги <a>.

Добавлено через 6 минут и 12 секунд
Вот так это будет выглядеть:
Код

foreach($tags as $id=>$tag)
    $text = preg_replace('#(?!<a[^>]+>)('.preg_quote($tag, '#').')(?!</a>)#iu', '<a href="tag/TAG['.$id.']">$1</a>', $text);

Этот же способ подойдет и к варианту ksnk.
PM MAIL ICQ Skype   Вверх
KgCoder
Дата 13.7.2009, 12:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 93
Регистрация: 6.3.2008
Где: KGstan

Репутация: нет
Всего: нет



enof, действительно. Спасибо... сейчас попробую.
PM MAIL   Вверх
KgCoder
Дата 13.7.2009, 13:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 93
Регистрация: 6.3.2008
Где: KGstan

Репутация: нет
Всего: нет



Простите, но у меня не выходит. Сделал так:
Код

    ...
    $result = db_query($query);
    while ($term = db_fetch_object($result)) {
      $glossary_term[$term->tid] = $term->name;
    }
    usort($glossary_term, "order_by_length");
    foreach ($glossary_term as $tid => $term) {
      $pattern = '#(?!<span class="advanced-glossary-term info-tip"[^>]+>)('.preg_quote($term, '#').')(?!</span>)#iu';
      $replacement = '<span class="advanced-glossary-term info-tip" id="term-' . $tid . '">' . $term . '</span>';
      if (variable_get('advanced_glossary_teaser', TRUE)) {
        $node->teaser = preg_replace($pattern, $replacement, $node->teaser,
          variable_get('advanced_glossary_link_first_only', true) ? 1 : -1);
      }
      $node->body = preg_replace($pattern, $replacement, $node->body,
        variable_get('advanced_glossary_link_first_only', true) ? 1 : -1);
    }
    ...

Резултат такой же:
Karakol river, goes near Karakol peak and enters Karakol city. Once more Karakol

PM MAIL   Вверх
enof
Дата 13.7.2009, 16:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 837
Регистрация: 23.1.2009
Где: Санкт-Петербург

Репутация: 1
Всего: 35



Код

$tags = array(
  5 => 'река Каракол',
  7 => 'город Каракол',
  21 => 'ущелье Каракол',
  1=>'Каракол',
);
foreach($tags as $id=>$tag)
    $text = preg_replace('#(?!<a[^>]+>)('.preg_quote($tag, '#').')(?!</a>)#iu', '<a href="tag/TAG['.$id.']">$1</a>', $text);
echo $text;

А так все работает?
PM MAIL ICQ Skype   Вверх
KgCoder
Дата 13.7.2009, 18:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 93
Регистрация: 6.3.2008
Где: KGstan

Репутация: нет
Всего: нет



Цитата(enof @  13.7.2009,  16:42 Найти цитируемый пост)
А так все работает? 

Нет :( Выделяет только Каракол четыре раза. :(
PM MAIL   Вверх
enof
Дата 13.7.2009, 18:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 837
Регистрация: 23.1.2009
Где: Санкт-Петербург

Репутация: 1
Всего: 35



хм, текст в какой кодировке?
PM MAIL ICQ Skype   Вверх
KgCoder
Дата 13.7.2009, 18:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 93
Регистрация: 6.3.2008
Где: KGstan

Репутация: нет
Всего: нет



Utf-8... а у вас работает?

Добавлено @ 18:56
Ваш вариант работает, оказывается файл сохранил как ansi. Но вот на инглише не работает:
Код

<?php
$text = 'Karakol river, goes near Karakol Peak and enters Karakol city. Once more Karakol.';
$tags = array(
  5 => 'Karakol river',
  7 => 'Karakol Peak',
  21 => 'Karakol city',
  1=>'Karakol',
);
foreach($tags as $id=>$tag)
    $text = preg_replace('#(?!<a[^>]+>)('.preg_quote($tag, '#').')(?!</a>)#iu', '<a href="tag/TAG['.$id.']">$1</a>', $text);
echo $text;


Добавлено @ 18:57
Вернее выделяет только Karakol четыре раза и всё.

Добавлено @ 18:58
Вот что произходит на инглише:
Код

<a href="tag/TAG[5]"><a href="tag/TAG[1]">Karakol</a> river</a>, 
goes near <a href="tag/TAG[7]"><a href="tag/TAG[1]">Karakol</a> Peak</a> 
and enters <a href="tag/TAG[21]"><a href="tag/TAG[1]">Karakol</a> city</a>. 
Once more <a href="tag/TAG[1]">Karakol</a>.


Это сообщение отредактировал(а) KgCoder - 13.7.2009, 19:00
PM MAIL   Вверх
enof
Дата 13.7.2009, 19:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 837
Регистрация: 23.1.2009
Где: Санкт-Петербург

Репутация: 1
Всего: 35



сорри, мой косяк, опять с проверками запутался. Сейчас подумаю.
PM MAIL ICQ Skype   Вверх
KgCoder
Дата 14.7.2009, 12:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 93
Регистрация: 6.3.2008
Где: KGstan

Репутация: нет
Всего: нет



Попробовал сам, через условия, но текст вообще не заменяется. :( Посмотрел сторонние модули, там используют mb_string и вообще функций типа preg не нашел. Код очень объемный там, и без комментов. В общем засада. :( Буду еще копать... надеюсь до завтра доживу smile
PM MAIL   Вверх
KgCoder
Дата 14.7.2009, 13:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 93
Регистрация: 6.3.2008
Где: KGstan

Репутация: нет
Всего: нет



Решил вопрос. Всем спасибо.
PM MAIL   Вверх
KgCoder
Дата 15.7.2009, 06:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 93
Регистрация: 6.3.2008
Где: KGstan

Репутация: нет
Всего: нет



Мне сказали, что можно это сделать через strpos и substr, при этом снизится нагрузка на сервер. Это правда?
PM MAIL   Вверх
KgCoder
Дата 16.7.2009, 06:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 93
Регистрация: 6.3.2008
Где: KGstan

Репутация: нет
Всего: нет



Что тут все такие пассивные стали?  smile В общем написал через strpos и substr получилось даже лучше по функциональности. Всем спасибо.
PM MAIL   Вверх
Страницы: (2) [Все] 1 2 
Ответ в темуСоздание новой темы Создание опроса
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | PHP: Тексты | Следующая тема »


 




[ Время генерации скрипта: 0.0751 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.