我想比较两个变量以查看它们是否相同,但我希望此比较不区分大小写。
例如,这将区分大小写:
if($var1 == $var2){
...
}
但我希望不区分大小写,我该如何处理?
如果您的字符串采用单字节编码,那就很简单:
if(strtolower($var1) === strtolower($var2))
如果您的字符串是 UTF-8,则必须考虑 Unicode 的复杂性:to-lower-case 和 to-upper-case 不是双射函数,即如果您有小写字符,请将其转换为大写,然后将其转换回小写,您可能不会得到相同的代码点(如果您以大写字符开头,情况也是如此)。
例如
Latin Capital Letter I with Dot Above, U+0130
) 是一个大写字符,“i”(Latin Small Letter I, U+0069
) 是其小写变体 – 而“i”的大写变体是“I”(Latin Capital Letter I, U+0049
)。Latin Small Letter Dotless I, U+0131
) 是小写字符,“I”(Latin Capital Letter I, U+0049
) 是其大写变体 – “I”的小写变体是“i”(Latin Small Letter I, U+0069
)因此
mb_strtolower('ı') === mb_strtolower('i')
返回 false,即使它们具有相同的大写字符。如果你真的想要一个不区分大小写的字符串比较函数,你必须比较大写版本和小写版本:
if(mb_strtolower($string1) === mb_strtolower($string2)
|| mb_strtoupper($string1) === mb_strtoupper($string2))
我已经从 https://codepoints.net (https://dumps.codepoints.net) 对 Unicode 数据库运行了查询,并且找到了 180 个代码点,当我发现这些代码点时,我发现了不同的字符采用小写字符的大写字母的小写字母,以及在采用大写字符的小写字母的大写字母时发现不同字符的 8 个代码点
但情况变得更糟:用户看到的同一个字素簇可能有多种编码方式:“ä”可能表示为
Latin Small Letter a with Diaeresis (U+00E4)
或Latin Small Letter A (U+0061)
和Combining Diaeresis (U+0308)
- 如果你比较它们在字节级别,这不会返回 true!
但是 Unicode 中有一个解决方案:标准化!有四种不同的形式:NFC、NFD、NFKC、NFKD。对于字符串比较,NFC 和 NFD 是等效的,NFKC 和 NFKD 是等效的。我会选择 NFKC,因为它比 NFKD 短,并且“ff”(
Latin Small Ligature ff, U+FB00
) 将转换为两个正常的“f”(但 2⁵ 也会扩展为 25...)。
结果函数变为:
function mb_is_string_equal_ci($string1, $string2) {
$string1_normalized = Normalizer::normalize($string1, Normalizer::FORM_KC);
$string2_normalized = Normalizer::normalize($string2, Normalizer::FORM_KC);
return mb_strtolower($string1_normalized) === mb_strtolower($string2_normalized)
|| mb_strtoupper($string1_normalized) === mb_strtoupper($string2_normalized);
}
请注意:
if(strtolower($var1) == strtolower($var2)){
}
为什么不:
if(strtolower($var1) == strtolower($var2)){
}
使用strcasecmp。
// to return boolean "are input strings equal?"
function mb_strcasecmp($s1,$s2): bool {
return mb_strlen($s1) == mb_strlen($s2) && 0 === mb_stripos($s1,$s2);
}