如何匹配UTF8编码的ZWSP(零宽空格)?是否存在Bug?
匹配/替换UTF-8编码的零宽空格(ZWSP)问题
ZWSP编码说明:
ZWSP: \x20\x0B ZWSP (UTF-8): \xE2\x80\x8B
我额外测试了非断空格(NBSP),表现符合预期。所有preg_replace均使用UTF-8模式/u,测试情况如下:
- 匹配NBSP正常:UTF-8编码输入被替换为空,输出为空字符串。
- 匹配ZWSP时,仅输入为非UTF-8编码时有效。
- 将ZWSP正则模式改为UTF-8编码版本,同时输入为UTF-8编码时,依然无法匹配。
核心问题
如何匹配UTF-8编码的ZWSP?或者这是一个Bug?
测试代码
$nbsp = '\xA0'; // 非断空格 $zwsp = '\x20\x0B'; // 零宽空格 $zwsp_utf8 = '\xE2\x80\x8B'; $input_nbsp_utf8 = "\xC2\xA0"; $input_zwsp = "\x20\x0B"; $input_zwsp_utf8 = "\xE2\x80\x8B"; // NBSP测试 echo "NBSP\n-----\n"; echo "in: $input_nbsp_utf8--\nhex: ".bin2hex($input_nbsp_utf8)."\n"; $output = preg_replace('/'.$nbsp.'/u', '', $input_nbsp_utf8); echo "out: $output--\nhex: ".bin2hex($output)."\n\n"; // ZWSP测试(输入:非UTF-8) echo "ZWSP (输入:非UTF-8)\n-----\n"; echo "in: $input_zwsp--\nhex: ".bin2hex($input_zwsp)."\n"; $output = preg_replace('/'.$zwsp.'/u', '', $input_zwsp); echo "out: $output--\nhex: ".bin2hex($output)."\n\n"; // ZWSP测试(输入:UTF-8) echo "ZWSP (输入:UTF-8)\n-----\n"; echo "in: $input_zwsp_utf8--\nhex: ".bin2hex($input_zwsp_utf8)."\n"; $output = preg_replace('/'.$zwsp.'/u', '', $input_zwsp_utf8); echo "out: $output--\nhex: ".bin2hex($output)."\n\n"; // ZWSP测试(模式:UTF-8,输入:UTF-8) echo "ZWSP (模式:UTF-8,输入:UTF-8)\n-----\n"; echo "in: $input_zwsp_utf8--\nhex: ".bin2hex($input_zwsp_utf8)."\n"; $output = preg_replace('/'.$zwsp_utf8.'/u', '', $input_zwsp_utf8); echo "out: $output--\nhex: ".bin2hex($output)."\n\n";
输出结果
NBSP ----- in: -- hex: c2a0 out: -- hex: ZWSP (输入:非UTF-8) ----- in: -- hex: 200b out: -- hex: ZWSP (输入:UTF-8) ----- in: -- hex: e2808b out: -- hex: e2808b // 预期输出应为空 ZWSP (模式:UTF-8,输入:UTF-8) ----- in: -- hex: e2808b out: -- hex: e2808b // 预期输出应为空
解决方案
问题根源在于正则模式的定义:你用单引号包裹十六进制转义序列,PHP不会解析这些转义,而是将其当作普通字符串(比如'\xE2\x80\x8B'实际是字符串\xE2\x80\x8B,而非对应的UTF-8字符)。
有两种正确的解决方式:
方式1:用双引号定义模式变量
让PHP解析十六进制转义,生成对应的ZWSP字符:
$zwsp_utf8 = "\xE2\x80\x8B"; // 双引号包裹,PHP解析为ZWSP字符 $output = preg_replace('/' . $zwsp_utf8 . '/u', '', $input_zwsp_utf8);
方式2:直接使用Unicode码点转义
ZWSP的Unicode码点是U+200B,直接在正则中用\u{200B}匹配,更直观且避免编码转义问题:
$output = preg_replace('/\u{200B}/u', '', $input_zwsp_utf8);
修改后的验证示例:
$input_zwsp_utf8 = "\xE2\x80\x8B"; // 方式1测试 $zwsp_utf8 = "\xE2\x80\x8B"; $output1 = preg_replace('/' . $zwsp_utf8 . '/u', '', $input_zwsp_utf8); // 方式2测试 $output2 = preg_replace('/\u{200B}/u', '', $input_zwsp_utf8); // 输出结果均为空 var_dump(bin2hex($output1)); // string(0) "" var_dump(bin2hex($output2)); // string(0) ""
以上两种方式都能正确匹配并替换UTF-8编码的ZWSP字符。
内容的提问来源于stack exchange,提问作者clarkk
相关产品推荐
相关产品推荐

