Сравнение строк без учета регистра

Я хотел бы сравнить две переменные, чтобы увидеть, одинаковы ли они, но я хочу, чтобы это сравнение было нечувствительным к регистру.

например, это будет чувствительно к регистру:

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

но я хочу, чтобы это было нечувствительным к регистру, как бы я подошел к этому?

6 ответов


Это достаточно просто, вам просто нужно позвонить strtolower() по обеим переменным.

Если вам нужно иметь дело с Unicode или международными наборами символов, вы можете использовать mb_strtolower().

обратите внимание, что другие ответы предлагают использовать strcasecmp()-что функция не обрабатывает многобайтовые символы, таким образом, результаты для любой строки UTF-8 будут фиктивными.


strcasecmp() возвращает 0, если строки одинаковы (кроме вариантов case), поэтому вы можете использовать:

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

если ваша строка находится в однобайтовой кодировке, это просто:

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).
  • "I" (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))

я запустил запрос к базе данных Unicode из https://codepoints.net (https://dumps.codepoints.net) и я нашел 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);
}

обратите внимание:

  • вам нужно intl пакета нормализатор
  • вы должны оптимизировать эту функцию, сначала проверив, являются ли они просто равны^^
  • вы можете использовать NFC вместо NFKC, потому что NFKC удаляет слишком много различий форматирования на ваш вкус
  • вы должны решить для себя, действительно ли вам нужна вся эта сложность или вы предпочитаете более простой вариант этой функции

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

использовать strcasecmp.


почему бы и нет:

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