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

| 我有一个PHP 5.3脚本显示我的网站用户,并想用它的旧名称替换某个俄罗斯城市(存储在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
已邀请:
我无法用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版本?在
pcre
部分检查
phpinfo()
。那就是我系统上的那个:
...
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
,我相信俄语字母会被整理到B16ѭ的拉丁字母B上。 因此,要么是PHP对其进行预格式化,要么PCRE在那里也不精确。测试您的
print PCRE_VERSION;
并查看更新日志。 无论如何,为了避免这个问题,我建议您只使用小写字母。它们更有可能与拉丁字母不同。
preg_replace(\'/волгоград/iu\', \'Сталинград\', $city);
附言:恶作剧!
在我的盒子上就像魅力一样...
<?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中吗?
也许尝试:mb_eregi_replace http://www.php.net/manual/zh/function.mb-eregi-replace.php mb_eregi_replace —用多字节支持替换正则表达式,忽略大小写
只是猜测,但是将字符串显式编码为unicode可能会有所帮助:
preg_replace(\'/Волгоград/iu\', utf8_encode(\'Сталинград\'), $city);
实际上,在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,并返回UTF-8版本。 问候!
对于那些支持庞大的旧代码库,在字符集和编码问题上苦苦挣扎,并且无法选择转换代码字符集的用户-这是一个答案:
//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
虽然您可以重写regexp以使用一些utf技巧,将代码转换为utf,但是当您使用庞大的代码库/数据库等时,这不是一个选择

要回复问题请先登录注册