Эта тема на forum.dklab.ru


Николай Булыгин: Реализация замены имен на ссылки
Ситуация такая: делаю сайт для филармонии, есть список концертов, в которых обозначены имена солистов, есть раздел солистов. Нужно заменить все имена солистов на соответсвующие им ссылки, причем можно было бы это делать при вбивании концертов, но пользователи очень плохо общаются с компютером в целом, поэтому они не смогут заменять самостоятельно. Пришла такая мысль, проходить по базе и заменять везде имя на ссылку через str_replace, но имя может быть разных видов, например: Петр, Петра и т.д. Как правильнее всего реализовать замену имен на ссылки с учетом сказанного выше?
Дмитрий Котеров:
Это достаточно сложно. Однако просклонять фамилии все же можно: см. в сторону ispell.
Хорошая статья по работе с ispell на PHP была в PHP Inside:
http://detail.phpclub.ru/download/okt2004/phpi7_2004.pdf
Там, правда, про поисковые запросы речь, но Ваша задача похожа. И - я не уверен, что оно будет работать для фамилий (там вроде только для словарных слов).

Корень из слова также выделяет вот эта штука (может, пригодится):
http://snowball.tartarus.org/russian/stemmer.html
Педагог:
Ну вот 90% решение

$arr=array();
$arr[]=array(name=>'Василий Пупкин',href=>'/VasilyPupkin/');
$arr[]=array(name=>'Иван Петров', href=>'/IvanPetrov/');

$text='Сегодня будет в исполнении Василия Пупкина (автор Петров Иван) увертюра "О любви".';

foreach($arr as $v)
{
$name=$v[name];
$sreg=trim(preg_replace('/[^\s]{2}\s/si','[^\s]+ ',$name.' '));
$text=preg_replace('/('.$sreg.')/si','<a href='.$v[href].'>\\1</a>',$text);

$name=preg_replace('/^([^\s]+)\s([^\s]+)$/si','\\2 \\1',$v[name]);
$sreg=trim(preg_replace('/[^\s]{2}\s/si','[^\s]+ ',$name.' '));
$text=preg_replace('/('.$sreg.')/si','<a href='.$v[href].'>\\1</a>',$text);
}

echo $text;

Maus:
Педагог:
что регов многовато, Вам не кажется?
Николай Булыгин:
Педагог:
Большое спасибо, сделал, работает.

Дмитрий Котеров:
Спасибо за линки!
Николай Булыгин:
Педагог:
Как модернизировать, данные регулярные выражения, для большей универсальности, чтобы заменялись фамилии написанные в разных регистрах. Столкнулся с такой проблемой, что локально на win 2k все работает, а у хостера *nix, и фамилии написанные в таком регистре: ПУПКИН, или ПуПкИн, не заменяются... Как решить такую проблему? Загонять в массив все возможные варианты не выход.
bæv:
Николай Булыгин, может, не реги "модернизировать", а перед вызовом регов нужную локаль поставить?
Николай Булыгин:
baev:
http://php.net/setlocale - это?

setlocale(LC_ALL,'ru_RU'); - так?
bæv:
это?
-- да

'ru_RU'

В разных операционных системах (и, даже, в разных версиях одной ОС) "названия" локалей отличаются -- узнавайте для своего конкретного случая.
Николай Булыгин:
В разных операционных системах (и, даже, в разных версиях одной ОС) "названия" локалей отличаются -- узнавайте для своего конкретного случая.
Как это проще всего узнать? phpinfo поможет?
bæv:
Как это проще всего узнать?

Спросить у хостера.
Николай Булыгин:
setlocale(LC_ALL,"ru_RU.CP1251");
Помогло вот это. Хмм... а в техподдержке хостера работают php программисты? Или же там в nix они не думая знают что это такое?
Николай Булыгин:
baev:
Педагог:
+1
Юрий Насретдинов:
там в nix они не думая знают что это такое
Педагог:
Педагог:
Как модернизировать, данные регулярные выражения, для большей универсальности, чтобы заменялись фамилии написанные в разных регистрах.
Странно! [^\s] - этоже не пробельные символы. Неужели сервер может считать русские как пробельные?
Николай Булыгин:
Педагог:
Наверное это так, установка локали помогла. Только вот теперь думаю, как бы передалать его, чтобы заменялись еще и фамилии с инициалами, пример: И. Петров, или Петров И.В., и т.д.
Педагог:
Ну тогда ужесточим исходные данные, чтобы проще было:

$arr=array();
$arr[]=array(f=>'Пупкин',i=>'Василий',o=>'Иванович',href=>'/VasilyPupkin/');

$text='Сегодня будет в исполнении Василия Пупкина (автор В.И.Пупкин) увертюра "О любви".';

foreach($arr as $v)
{
$name=$v[f].' '.$v[i].' '.$v[o]; $text=insertHref($text,$name,$v[href]);
$name=$v[i].' '.$v[o].' '.$v[f]; $text=insertHref($text,$name,$v[href]);
$name=$v[f].' '.$v[i]; $text=insertHref($text,$name,$v[href]);
$name=$v[i].' '.$v[f]; $text=insertHref($text,$name,$v[href]);

$name=$v[f].' '.$v[i][0].'\.\s*'.$v[o][0].'\.'; $text=insertHref($text,$name,$v[href]);
$name=$v[i][0].'\.\s*'.$v[o][0].'\.\s*'.$v[f]; $text=insertHref($text,$name,$v[href]);
$name=$v[f].' '.$v[i][0].'.'; $text=insertHref($text,$name,$v[href]);
$name=$v[i][0].'.\s*'.$v[f]; $text=insertHref($text,$name,$v[href]);

// удаляем появляющиеся вложенные ссылки
$t=''; while ($text!=$t) $text=preg_replace('{(<a [^>]+>[^<>]*)<a [^>]+>([^<>]*)</a>([^<>]*</a>)}si','\\1\\2\\3',$t=$text);
}


function insertHref($text,$name,$href)
{
$sreg=trim(preg_replace('/[а-яА-Я\w]{2}([^а-яА-Я\w])/si','[а-яА-Я\w]+\\1',$name.' '));
$text=preg_replace('/('.$sreg.')/si','<a href='.$href.'>\\1</a>',$text);
return $text;
}

echo $text;
Приведенное регулярное выражение вроде не должно зависить от локали.
Николай Булыгин:
Педагог:
У некоторых солистов неизвестно отчество, поэтому работает не везде. А так отлично! Спасибо!
Педагог:
Педагог:
У некоторых солистов неизвестно отчество, поэтому работает не везде. А так отлично! Спасибо! Например на какой строке не работает? Я вроде-бы "без отчества" предусматривал.
Николай Булыгин:
Педагог:

$arr[]=array(f=>'Пупкин',i=>'Василий',o=>'',href=>'/VasilyPupkin/');
$text='Сегодня будет в исполнении Василия Пупкина (автор Пупкин В.) соавтор Пупкин В.И. увертюра "О любви" в ролях: Пупкин В. И., а так же В. И. Пупкин';

Пупкин В.) - заменена на ссылку со скобкой
Пупкин В.И. - заменено только Пупкин В.И
В. И. Пупкин - не заменено вообще
bæv:
[^\s] - этоже не пробельные символы. Неужели сервер может считать русские как пробельные?

Дело не в \s, а в \i -- если система не знает, что символы русские, то и не знает, что "А" и "а" это одна и та же буква.
Педагог:

Пупкин В.) - заменена на ссылку со скобкой
Тут лажанулся, надо точки заслешить, сейчас подправлю в том сообщении.


Пупкин В.И. - заменено только Пупкин В.И
В. И. Пупкин - не заменено вообще
Тут выхода два: или обратиться в отдел кадров, или спросить у того кто пишет статью : "Откуда ты знаешь его отчество?".
Педагог:
[^\s] - этоже не пробельные символы. Неужели сервер может считать русские как пробельные?Дело не в \s, а в \i -- если система не знает, что символы русские, то и не знает, что "А" и "а" это одна и та же буква.
Мне кажется что при любой локали и присутствия/отстутствия опции i следующее выражение вернет true, :preg_match('{[^\s]+}si','АаЯяSsZz')Разве не так?

Я думаю просто в тексте встречались фамилии набранные большими буквами, тогда действительно без настройки локали не обойтись. Или надо продублировать информации два раза: "Пупкин" и "ПУПКИН". Главное чтобы не набирали вот так "ПуПкИн" :)
Николай Булыгин:
Педагог:
Вы меня просто выручили, спасибо!
~Cache~:
setlocale(LC_ALL,"ru_RU.CP1251");
Помогло вот это.
У меня эта функция вызывает ошибку 'Warning: setlocale(): Passing locale category name as string is deprecated. Use the LC_* -constants instead. in '...

Так и должно быть???


З.Ы. у моего хостера тоже: setlocale(LC_ALL,"ru_RU.CP1251");
к тому же по какой-то причине не помогает с данными вставляемыми в параметр value="" в форме ?! :/

На Денвере все работает - у хостера - нет (((

У хостера:

echo setlocale(LC_ALL, '')."<br>";
echo SETLOCALE ("LC_ALL", "ru_RU.CP1251");

Получаем:
C
Warning: setlocale(): Passing locale category name as string is deprecated. Use the LC_* -constants instead. in /home/... on line 21
ru_RU.CP1251

где:
C => setlocale(LC_ALL, '');
ru_RU.CP1251 => SETLOCALE ("LC_ALL", "ru_RU.CP1251");

Что делать? Так и должно быть (про ошибку)? Из-за чего может быть пробела в формах (парам. value)?
Maus:
~Cache~
Вы зачем LC_ALL в кавычках написали? Это раз. Два: нетрудно заметить, что строчек две, а warning - один. Вывод из этого - очевидный
~Cache~:
~Cache~
Вы зачем LC_ALL в кавычках написали? Это раз. Два: нетрудно заметить, что строчек две, а warning - один. Вывод из этого - очевидный

После 2-х суток без сна и слона в глазу не заметишь))

Sorry, за мою невнимательность и спасибо за ответ.

Эта тема на forum.dklab.ru