从字符串中删除PHP的多字节空格

7
我想使用 preg_replace 来从字符串输入中消除日语全角空格 " ",但最终得到的是一个损坏的多字节字符串。
我更喜欢 preg_replace 而不是 str_replace。这是一个样例代码:
$keywords = ' ラメ単色';
$keywords = str_replace(array(' ', ' '), ' ', urldecode($keywords)); // 输出:'ラメ単色'

$keywords = preg_replace("@[  ]@", ' ',urldecode($keywords)); // 输出:'�� ��単色'
有人知道为什么会出现这种情况以及如何解决吗?

$keywords' ラメ単色' 是相同的吗? - alex
是的,匆忙复制并编辑了它。 - shawndreck
4个回答

9

在您的正则表达式中添加u标志。这将使RegEx引擎将输入字符串视为UTF-8。

$keywords = preg_replace("@[  ]@u", ' ',urldecode($keywords));
// outputs :'ラメ単色'

CodePad.

它混淆字符串的原因是因为对于正则表达式引擎来说,您的替换字符20(空格)或e3 80 80(表意空格)不被视为两个字符,而是单独的字节20e380

当您查看要扫描的字符串的字节序列时,我们得到e3 80 80 e3 83 a9 e3 83 a1 e5 8d 98 e8 89 b2。我们知道第一个字符是表意空格,但由于PHP将其视为一系列字节,因此它会单独替换前四个字节,因为它们与正则表达式引擎正在扫描的单个字节匹配。

至于导致�(替换字符)混淆的问题,我们可以看到这是因为字节e3在字符串中进一步出现了。 e3字节是一个三字节长的日语字符的起始字节,例如e3 83 a9(片假名RA字母)。 当将前导的e3替换为20(空格)时,它不再成为有效的UTF-8序列。

当启用u标志时,正则表达式引擎将字符串视为UTF-8,并且不会按字节处理字符类中的字符。


我会接受你的回答,因为它使用了我喜欢的 preg_replace 函数。不过 mb_ereg_replace 也可以完成任务。谢谢! - shawndreck

2
为避免额外的问题,还要考虑明确设置内部编码到你的 mb_* 函数解决方案中:
mb_internal_encoding("UTF-8");

1

深入文档总是有好处的。我发现 preg_* 相关函数不适用于多字节字符优化。相反,应该使用 mb_ereg_* 和 mb_* 函数。我通过重构代码解决了这个小问题,代码如下:

$keywords = ' ラメ単色';
$pattern = " "/*ascii whitespace*/ . " "/*multi-byte whitespace*/;
$keywords = trim(
    mb_ereg_replace("[{$pattern}]+", ' ',urldecode($keywords))); // 输出:'ラメ単色'

还是要感谢大家!


-1

使用这个

$keywords = preg_replace('/\s+/', ' ',urldecode($keywords));

1
那不会匹配OP想要删除的所有字符。 - alex

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