PHP:UTF8中的西里尔字符串的不区分大小写的preg_replace

时间:2011-03-28 11:35:34

标签: php utf-8 internationalization preg-replace

我有a PHP 5.3 script显示我网站的用户,并希望用其旧名称替换某个俄罗斯城市(存储在PostgreSQL 8.4.7数据库中的UTF8 + CentOS 5.5 / 64位Linux中)(它是内幕笑话:

preg_replace('/Волгоград/iu', 'Сталинград', $city);

不幸的是,这仅适用于完全匹配:Волгоград

这不适用于其他情况,例如ВОЛГОГРАДволгоград

如果我将源代码修改为

preg_replace('/[Вв]олгоград/iu', 'Сталинград', $city);

然后它会抓住上面的第二个案例。

有人知道它发生了什么以及如何解决它(假设我不想为每个字母写 [Xx] )?

谢谢! 亚历

更新

# 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

9 个答案:

答案 0 :(得分:5)

我无法使用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) "Сталинград"

您的PHP使用哪种PCRE版本?检查phpinfo()部分pcre。这就是我系统中的那个:

...
pcre

PCRE (Perl Compatible Regular Expressions) Support => enabled
PCRE Library Version => 8.02 2010-03-19
...

答案 1 :(得分:4)

你可以跳过正则表达式,它在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]."

这引起了我的兴趣,所以I asked a question

答案 2 :(得分:4)

这个问题解决了这个问题:

setlocale(LC_ALL, 'ru_RU.CP1251', 'rus_RUS.CP1251', 'Russian_Russia.1251');

答案 3 :(得分:2)

我复制+粘贴你的大В。它确实是U+D092,而不是普通的拉丁语B。但是因为它们看起来很相似:ВB我相信俄语字母被整理到U+0042的拉丁语B上。

因此要么是PHP预先格式化它,要么PCRE在那里也有些不精确。测试您的print PCRE_VERSION;并查看更改日志。

无论如何,为了避免这个问题,我建议你只使用小写字母。它们更可能与拉丁字母不同。

preg_replace('/волгоград/iu', 'Сталинград', $city);

P.S。:笑话里面的笑话!

答案 4 :(得分:1)

在我的盒子上像魅力一样......

<?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?

答案 5 :(得分:1)

也许试试:mb_eregi_replace http://www.php.net/manual/en/function.mb-eregi-replace.php

  

mb_eregi_replace - 使用忽略大小写的多字节支持替换正则表达式

答案 6 :(得分:0)

只是猜测,但明确地将字符串编码为unicode可能会有所帮助:

preg_replace('/Волгоград/iu', utf8_encode('Сталинград'), $city);

答案 7 :(得分:0)

实际上在Windows上使用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成功替换(case-initiveitively)'гъз'并返回UTF-8版本。

问候!

答案 8 :(得分:0)

对于那些支持巨大遗留代码库的人来说,与charset&amp;编码问题,没有转换代码字符集的选项 - 这是一个答案:

//for 
setlocale(LC_ALL, 'ru_RU.cp1251');  
//(or any other locale) to take effect, 
//you MUST generate system locale, i.e.

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,但是当您使用庞大的代码库/数据库等时,它不是一个选项