You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何检测字符串中是否包含组合字符而非预组合带波浪线字符?

检测字符串中的Unicode组合字符

你遇到的问题核心是ord()只能处理单字节,没法识别UTF-8编码下的完整Unicode字符单元——组合字符(比如U+0303波浪线)在UTF-8里是多字节,ord()遍历拿到的是单个字节值,不是对应的Unicode码点,自然检测不到。

下面给两个实用的PHP解决方案:

方法一:用正则快速检测

利用Unicode字符属性,直接匹配所有组合标记类字符(\p{M}),配合u修饰符开启Unicode模式:

$a = 'Anão'; // 预组合ã(U+00E3)
$b = 'Anão'; // a(U+0061)+ 组合波浪线(U+0303)

// 检测是否包含组合字符
function hasCombiningChars(string $str): bool {
    return preg_match('/\p{M}/u', $str) === 1;
}

var_dump(hasCombiningChars($a)); // bool(false)
var_dump(hasCombiningChars($b)); // bool(true)

\p{M}匹配所有Unicode标记字符,包括非间距组合符(比如波浪线)、间距组合符和封闭组合符,u修饰符确保正则正确解析UTF-8字符串。

方法二:遍历字符逐个检查

如果需要定位具体的组合字符,可以用mb_str_split拆分出每个Unicode字符,再通过IntlChar类判断字符类别(需开启intl扩展):

use IntlChar;

function findCombiningChars(string $str): array {
    $combiningChars = [];
    $chars = mb_str_split($str);
    
    foreach ($chars as $char) {
        $category = IntlChar::getUnicodeCategory($char);
        // 匹配所有组合标记类别的字符
        if (in_array($category, [
            IntlChar::CHAR_CATEGORY_NON_SPACING_MARK,
            IntlChar::CHAR_CATEGORY_SPACING_COMBINING_MARK,
            IntlChar::CHAR_CATEGORY_ENCLOSING_MARK
        ])) {
            $combiningChars[] = [
                'char' => $char,
                'codePoint' => IntlChar::ord($char)
            ];
        }
    }
    
    return $combiningChars;
}

print_r(findCombiningChars($b));
// 输出:Array ( [0] => Array ( [char] => ̃ [codePoint] => 771 ) )

额外提示:字符串归一化

如果需要让两个视觉一致的字符串内容完全相等,可以用Normalizer类(同样需intl扩展)把分解形式转成预组合形式:

$normalizedB = Normalizer::normalize($b, Normalizer::FORM_C);
var_dump($a === $normalizedB); // bool(true)

FORM_C会将分解的字符组合(a+波浪线)合并成预组合字符(ã),统一字符串的编码表示。

内容的提问来源于stack exchange,提问作者Carlos Missé

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 12:10:31