У меня есть скрипт PHP 5.3, отображающий пользователей моего веб-сайта и хотел бы заменить некий российский город (хранящийся в UTF8 в базе данных PostgreSQL 8.4.7 + CentOS 5.5 / 64 бит Linux) по его более раннему имени (это инсайдерская шутка) :
preg_replace('/Волгоград/iu', 'Сталинград', $city);
К сожалению, это работает только для точных матчей: Волгоград .
Это не работает для других случаев, таких как ВОЛГОГРАД или волгоград .
Если я изменю свой исходный код на
preg_replace('/[Вв]олгоград/iu', 'Сталинград', $city);
то он поймает второй случай выше.
Кто-нибудь знает, что происходит и как это исправить (если я не хочу писать [Xx] для каждой буквы)?
Спасибо! Alex
ОБНОВИТЬ:
# rpm -qa|grep php php53-bcmath-5.3.3-1.el5 php53-gd-5.3.3-1.el5 php53-common-5.3.3-1.el5 php53-pdo-5.3.3-1.el5 php53-mbstring-5.3.3-1.el5 php53-xml-5.3.3-1.el5 php53-5.3.3-1.el5 php53-cli-5.3.3-1.el5 php53-pgsql-5.3.3-1.el5 # rpm -qa|grep pcre pcre-6.6-2.el5_1.7
Я не могу воспроизвести вашу проблему с помощью PHP 5.3.3 ( PHP 5.3.3-1ubuntu9.3 with Suhosin-Patch (cli)
):
$str1 = 'Волгоград'; $str2 = 'ВОЛГОГРАД'; $str3 = 'волгоград'; var_dump(preg_replace('/Волгоград/iu', 'Сталинград', $str1)); var_dump(preg_replace('/Волгоград/iu', 'Сталинград', $str2)); var_dump(preg_replace('/Волгоград/iu', 'Сталинград', $str3));
выходы
string(20) "Сталинград" string(20) "Сталинград" string(20) "Сталинград"
Какая версия PCRE использует ваш PHP? Проверьте phpinfo()
для phpinfo()
pcre
. Это та, что в моей системе:
... pcre PCRE (Perl Compatible Regular Expressions) Support => enabled PCRE Library Version => 8.02 2010-03-19 ...
Вы можете пропустить регулярное выражение, это сработало для меня в PHP 5.2.11 🙂
$city = 'Unfortunately this only works for exact matches: Волгоград. This does not work for other cases, like ВОЛГОГРАД or волгоград.'; echo str_ireplace('Волгоград', '[found]', $city);
"Unfortunately this only works for exact matches: [found]. This does not work for other cases, like [found] or [found]."
Это заинтриговало меня, поэтому я задал вопрос .
Это решило проблему:
setlocale(LC_ALL, 'ru_RU.CP1251', 'rus_RUS.CP1251', 'Russian_Russia.1251');
Я копирую + вставлял свой большой В
Это действительно U+D092
, а не нормальный латинский B
Но так как они похожи друг на друга: ВB
Я считаю, что русское письмо сопоставляется с латиницей B U+0042
.
Таким образом, либо это предварительная форматирование PHP, либо, возможно, PCRE тоже неточно. Проверьте свою print PCRE_VERSION;
и загляните в журнал изменений.
Во всяком случае, чтобы избежать проблемы, я предлагаю вам использовать только строчные буквы. Они, скорее всего, отличаются от латинского алфавита.
preg_replace('/волгоград/iu', 'Сталинград', $city);
PS: Зло внутри шутки!
Работает как очарование на моей коробке …
<?php $city = 'Волгоград'; var_dump(preg_match('/волгоград/ui', $city)); var_dump(preg_match('/ВОЛГОГРАД/ui', $city)); var_dump(preg_replace('/волгоград/ui', 'Сталинград', $city)); var_dump(preg_replace('/ВОЛГОГРАД/ui', 'Сталинград', $city));
Вывод:
int 1 int 1 string 'Сталинград' (length=20) string 'Сталинград' (length=20)
Вы уверены, что входные данные ($ city) находятся в UTF8?
Просто угадать, но явно кодировать строку в Юникод может помочь:
preg_replace('/Волгоград/iu', utf8_encode('Сталинград'), $city);
Возможно, попробуйте: mb_eregi_replace http://www.php.net/manual/en/function.mb-eregi-replace.php
mb_eregi_replace – Заменить регулярное выражение на многобайтную поддержку, игнорируя регистр
На самом деле с PHP 5.2.x на окнах выбранный для решаемого ответа не работал для меня.
Мне пришлось переходить на Windows-1251, чтобы он работал.
Здесь вы приводите пример:
$new_content = preg_replace(iconv('UTF-8', 'Windows-1251', "/\bгъз\b/i"), iconv('UTF-8', 'Windows-1251', "YYYYYY"), iconv('UTF-8', 'Windows-1251', "ти си gyz gyz гъз ГЪЗ gyzgyz гЪз gyz")); $new_content = iconv('Windows-1251', 'UTF-8', $new_content);
Приведенный выше пример заменит успешно (без учета случая) «гъз» на YYYYYY и вернет вам версию UTF-8.
С уважением!
для тех, кто поддерживает огромную базу устаревших кодов, борясь с проблемами кодировки и кодирования и без возможности конвертировать кодировку кода – вот ответ:
//for setlocale(LC_ALL, 'ru_RU.cp1251'); //(or any other locale) to take effect, //you MUST generate system locale, ie sudo su #view supported locales #less /usr/share/i18n/SUPPORTED echo "ru_RU.cp1251 CP1251" >> /var/lib/locales/supported.d/local dpkg-reconfigure locales exit #and (for ubuntu/debian) apt-get install php5-intl
в то время как вы можете переписать свое регулярное выражение для использования некоторых трюков utf, конвертировать ваш код в utf, это не вариант, когда вы работаете с огромной базой данных / базы данных и т. д.