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


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

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

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

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

6 56

6 ответов:

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

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

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

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

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

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

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

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

например.

  • "я" (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);
}

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

  • вам нужно международный пакета нормализатор
  • вы должны оптимизировать эту функцию, сначала проверяя, если они просто равны^^
  • вы можете использовать NFC вместо NFKC, потому что NFKC удаляет слишком много различий форматирования на ваш вкус
  • вы должны решить для себя, если вам действительно нужны все эти сложности, или если вы предпочитаете более простой вариант этой функции
if(strtolower($var1) == strtolower($var2)){
}

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

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

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