Сравнение строк без учета регистра
Я хотел бы сравнить две переменные, чтобы увидеть, являются ли они одинаковыми, но я хочу, чтобы это сравнение было нечувствительным к регистру.
например, это будет чувствительно к регистру:
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, вы должны рассмотреть сложность в Юникоде: в нижнем регистре и верхнем регистре не биективных функций, т. е. если у вас есть нижний регистр символов, преобразовать его в верхний регистр, и превратить его обратно в нижний регистр, вы не можете в конечном итоге с тем же кодом точки (и то же самое справедливо, если вы начинаете с заглавной характер.)
например.
- "я" (
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 удаляет слишком много различий форматирования на ваш вкус
- вы должны решить для себя, если вам действительно нужны все эти сложности, или если вы предпочитаете более простой вариант этой функции
использовать strcasecmp.