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