在UTF-8中匹配单词边界的PHP正则表达式

14

我在一个utf-8编码的php文件中有以下的php代码:

var_dump(setlocale(LC_CTYPE, 'de_DE.utf8', 'German_Germany.utf-8', 'de_DE', 'german'));
var_dump(mb_internal_encoding());
var_dump(mb_internal_encoding('utf-8'));
var_dump(mb_internal_encoding());
var_dump(mb_regex_encoding());
var_dump(mb_regex_encoding('utf-8'));
var_dump(mb_regex_encoding());
var_dump(preg_replace('/\bweiß\b/iu', 'weiss', 'weißbier'));
我想让最后一个正则表达式仅替换完整的单词而不是单词的部分。

在我的Windows电脑上,它返回:

string 'German_Germany.1252' (length=19)
string 'ISO-8859-1' (length=10)
boolean true
string 'UTF-8' (length=5)
string 'EUC-JP' (length=6)
boolean true
string 'UTF-8' (length=5)
string 'weißbier' (length=9)

在Web服务器(Linux)上,我得到:

string(10) "de_DE.utf8"
string(10) "ISO-8859-1"
bool(true)
string(5) "UTF-8"
string(10) "ISO-8859-1"
bool(true)
string(5) "UTF-8"
string(9) "weissbier"

因此,该正则表达式在Windows上按照我的预期工作,但在Linux上却不是。

所以主要问题是,我应该如何编写我的正则表达式才能只在单词边界进行匹配?

另一个问题是我如何让Windows知道我想在PHP应用程序中使用UTF-8。

4个回答

19
即使在UTF-8模式下,标准的类别简写如\w和\b并不支持Unicode。你必须使用Unicode简写,正如你所发现的那样,但是你可以通过使用环视而不是交替来使其更加优雅:

即使在UTF-8模式下,标准的类别简写如\w\b并不支持Unicode。您只需要使用Unicode简写,就像您已经解决的那样,但您可以使用环视代替交替,从而使其看起来更加简单明了:

/(?<!\pL)weiß(?!\pL)/u

同时请注意,我在Unicode类别简写中省略了花括号;当类名只有一个字母时,您可以这样做。


1
+1 - 最近的PHP版本中,\w\b似乎按预期工作,但它们绝对不是您可以依赖的东西,因为当您部署应用程序时它们可能会出现问题。 - Álvaro González
请注意这里的被接受的答案:https://dev59.com/o1PTa4cB1Zd3GeqPlasV 如果您想使用Unicode简写! - Andreas W. Wylach

5

猜测这与Bug #52971有关。

PCRE元字符(例如\b\w)无法与Unicode字符串一起使用。

已经在PHP 5.3.4中修复

PCRE扩展:修复了错误#52971PCRE-Meta-Characters不能与utf-8一起工作)。


4

这是我目前找到的内容。通过像这样重新编写搜索和替换模式:

$before = '(^|[^\p{L}])';
$after = '([^\p{L}]|$)';
var_dump(preg_replace('/'.$before.'weiß'.$after.'/iu', '$1weiss$2', 'weißbier'));
// Test some other cases:
var_dump(preg_replace('/'.$before.'weiß'.$after.'/iu', '$1weiss$2', 'weiß'));
var_dump(preg_replace('/'.$before.'weiß'.$after.'/iu', '$1weiss$2', 'weiß bier'));
var_dump(preg_replace('/'.$before.'weiß'.$after.'/iu', '$1weiss$2', ' weiß'));

我得到了想要的结果:

string 'weißbier' (length=9)
string 'weiss' (length=5)
string 'weiss bier' (length=10)
string ' weiss' (length=6)

在我运行Apache的Windows计算机和托管的Linux Web服务器上,我都希望有更好的方法来做这件事。此外,我仍然想将我的Windows计算机设置为UTF-8编码。

0
根据这个评论,这是PHP中的一个bug。使用\W代替\b有什么好处吗?

是的,那是10年前的事了。 - ntd
是的,他们是。现在好了吗? - ntd

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接