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