不区分大小写的字符串比较


Answers:


114

这很简单;您只需要调用strtolower()两个变量。

如果您需要处理Unicode或国际字符集,则可以使用mb_strtolower()

请注意,其他答案建议使用strcasecmp()-该函数不能处理多字节字符,因此任何UTF-8字符串的结果都是虚假的。


1
在一般情况下,我相信MySQL的字符串比较不区分大小写。也就是说,'A' = 'a'是真的。参考:dev.mysql.com/doc/refman/5.0/en/case-sensitivity.html
asthasr

4
抱歉,我不是MySQL专家。您可能希望将其作为单独的问题发布。
asthasr 2011年

1
请注意,使用此方法可能会遇到字符集问题(例如,如果您使用一些奇怪的UTF-8字符),在这种情况下,请mb_strtolower()改用。
Balmipour

4
不幸的是,这并不是那么简单:在Unicode中,小写字母的大写字母char可能与您开始时的字母不同-反之亦然。即您必须与mb_strtolower()和mb_strttoupper()比较。
击败

1
@robotik我无法编辑评论,但您可以从我的答案中复制,那里是正确的;)
击败Beat

71

strcasecmp() 如果字符串相同(除了大小写不同),则返回0,因此可以使用:

if (strcasecmp($var1, $var2) == 0) {
}

3
只记得要测试== 0; 这是违反直觉的,因为写“ if(strcasecmp($ var1,$ var2)){...”非常诱人,但在这种情况下,0表示等于而不是像通常那样的虚假notequal。
Chirael 2014年

6
strcasecmp()不处理多字节字符,因此无法应付Unicode。
asthasr

15

如果您的字符串采用单字节编码,则很简单:

if(strtolower($var1) === strtolower($var2))

如果字符串是UTF-8,则必须考虑Unicode的复杂性:小写和大写不是双射函数,即,如果您具有小写字符,则将其转换为大写并进行转换回到小写,您可能不会以相同的代码点结尾(如果以大写字母开头,则同样适用)。

例如

  • “İ”(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.nethttps://dumps.codepoints.net)对Unicode数据库进行了查询,我发现180个代码点在使用小写字符时发现了另一个字符大写字母的小写字母,以及8个代码点,当我将大写字母的字母的小写字母的大写字母转换为8个代码点时

但是,情况变得更糟:用户看到的同一个字素簇可能有多种编码方式:“ä”可能用asLatin Small Letter a with Diaeresis (U+00E4)或asLatin Small Letter A (U+0061)和as表示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);
}

请注意:

  • 您需要用于Normalizerintl
  • 您应该通过首先检查它们是否相等来优化此功能^^
  • 您可能要使用NFC而不是NFKC,因为NFKC消除了太多符合您口味的格式设置
  • 您必须自己决定,是否真的需要所有这些复杂性,或者是否更喜欢此功能的简单变体

1
if(strtolower($var1) == strtolower($var2)){
}

尽管我理解此技术并且它是非常基本的,但这不是一个慷慨的或解释性的答案。当新的研究人员看到仅旧代码的答案时,他们将开始认为这是Stackoverflow上的一个完全可以接受的答案。请榜样更好地发布行为,以进行教育,而不是倾倒解决方案并浪费时间。
mickmackusa

0

为什么不:

if(strtolower($var1) == strtolower($var2)){
}

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.