баги добавления xml-разметки при помощи preg_replace

comp_ling

Новичок
баги добавления xml-разметки при помощи preg_replace

Добрый вечер!
Задача такова: найт все однокореные слова в тексте и добавить к ним xml-разметку типа "<w id='' n=''>$i</w> ", где $i - нжное слово.
Проблема: создание лишних записей по количеству найденных совпадений, вызванное скорее всего неверным использованием preg_replace. То есть: если слово "царь" встретится 2 раза на выход получаю "<w id='' n=''> <w id='' n=''>царь</w> </w>" а надо "<w id='' n=''>царь</w>".

Мой код:
PHP:
$all_text = "царь прав, царь должен царю.";
$arr_all = array();
$arr_all = preg_split("/[ |\t]+/",$all_text);

// ищу слова по псевдооснове (сочетанию букв)
$rez = preg_grep('/царь/i',$arr_all);

foreach ($rez as $i)
{
$pattern[]="/$i/";
$replacement[] = "<w id='' n=''>$i</w> ";
};
reset($rez); 
$arr_plus = preg_replace($pattern,$replacement,$rez);
print(htmlspecialchars(print_r($arr_plus,true)));
?>
Подозреваю, чт можно использовать srt_replace, но сама не дотопала как
 

Vallar_ultra

Любитель выпить :)
Мы не ищем лёгких путей, я понимаю....
Тебе надо заменить все слова в которых есть подстрока "царь"? Если да:

PHP:
$all_text = "царь прав, царь должен царю. царский указ!";
$word = 'царь';
$all_text = preg_replace("/(([a-zа-яёЁ]*)?{$word}([a-zа-яёЁ]*)?)/i","<w id='' n=''>$1</w>",$all_text);
var_dump($all_text);
-~{}~ 05.02.07 01:42:

>Подозреваю, чт можно использовать srt_replace, но сама не дотопала как

Не надо топать в ту сторону. Тут всё нормально!
 

comp_ling

Новичок
Гениально! Только жаль сама не додумала, потопилась спросить.

Спасибо!

Топик закрыт!
 

WP

^_^
Задача не решена ;) Даже близко. Во-первых ты столкнешься с необходимостью ввода корней слов вручную, во-вторых замен (вызовов preg_replace) будет очень много, и они могут пересекаться. В-третьих если ты захочешь (а ты хочешь) вставлять в параметры тега w что-то кроме статичных строк, то это не представится возможным.

Мое решение:
PHP:
require_once 'stem.php';
$text = 'царь прав, царь должен царю. царский указ!';
class Replace
{
 function callback($m)
 {
  static $stems = array();
  static $id = 0;
  $word = strtolower($m[0]);
  $stem = $this->stemmer->stem_word($word);
  if (!isset($stems[$stem])) {$info = $stems[$stem] = array($id++);}
  else {$info = $stems[$stem];}
  return '<w id='.$info[0].'>'.$word.'</w>';
 }
}
$replace = new Replace;
$replace->stemmer = new Lingua_Stem_Ru;
$text = preg_replace_callback('~\w+~',array($replace,'callback'),$text);
echo $text;
/*<w id=0>царь</w> <w id=1>прав</w>, <w id=0>царь</w> <w id=2>должен</w> <w id=0>царю</w>. <w id=0>царский</w> <w id=3>указ</w>!*/
stem.php ты можешь скачать по адресу http://whitephoenix.ru/stem.phps
 

Vallar_ultra

Любитель выпить :)
WP

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

WP

^_^
Vallar_ultra
Это проблема не моя, а создателя стеммера (Портера).

Пополнил регулярное выражение в стеммере суффиксом "ск".
 

comp_ling

Новичок
Доброе утро.
И все же первый вариант меня больше устраивает. Будут размечаться тексты первой четверти 18 века, поэтому все "псевдоосновы" все равно в ручную вводить (там бардак с вариантами написания), а это исключиет добавление нестатичных переменных - несколько комбинаций для поиска будут иметь свой id, который будет задаваться мной. И размечать нужно не все слова, а только нужные. Если бы надо было все - было бы проще воспользоваться нормальным лемматизатором с хорошей базой словарей. Мне же будут нужны только некоторые. И риск пересечения при таком подходе кажется минимальным, хотя... Все бывает.
Еще раз спасибо всем.
 
Сверху