Я храню varchar в таблице MySQL utf8 и использую сопоставление utf8_general_ci. У меня есть уникальный индекс varchar. Я хотел бы провести сравнение строк в PHP, которое эквивалентно тому, что MySQL будет делать с индексом.
Конкретный пример заключается в том, что я хотел бы иметь возможность определить, что 'a' считается эквивалентом 'À' в PHP, прежде чем это произойдет:
mysql> insert UniTest (str) values ('a');
Query OK, 1 row affected (0.00 sec)
mysql> insert UniTest (str) values ('À');
ERROR 1062 (23000): Duplicate entry 'À' for key 1
Было бы разумно просто позволить MySQL выполнять эту работу, отправив в MySQL запрос, например:
SELECT CASE WHEN '$a' = '$b' THEN 1 ELSE 0 END
Вы можете однократно перебрать весь интересующий декартов набор символов, соединенный с самим собой, и построить стандартный ассоциативный массив php наборов эквивалентности.
for each $char1 in $charset { for each $char2 in $charset { $charmatch[$char1][$char2] = mysqlTestMatch($char1, $char2)); } }
Затем вам нужно будет проверить каждый строковый символ за символом, чтобы увидеть, а) они одинаковы, или, если нет, б) они эквивалентны.
Почему бы вам просто не позволить MySQL решить, существует ли уже запись с таким же ключом?
Вы можете запустить запрос SELECT
, чтобы узнать, существует ли уже запись с этим атрибутом:
SELECT 1
FROM UniTest
WHERE str = "À"
Или вы просто можете попробовать вставить новую запись и использовать функции mysql_error () и mysql_errno (), чтобы узнать, произошла ли ошибка.
Сопоставление не имеет ничего общего с хранилищем. Вам нужно установить кодировку, чтобы определить кодировку хранилища. Сопоставление определяет, как должны происходить сравнение и сортировка. Сопоставление должно учитывать кодировку, но в остальном она не имеет ничего общего с кодировкой.
Чтобы ответить на ваш вопрос, вы можете использовать iconv
для перевода текста, а затем сравнить его. Например:
function compare($s1, $s2) {
return strcmp(
iconv('UTF-8', 'ISO-8859-1//TRANSLIT', $s1),
iconv('UTF-8', 'ISO-8859-1//TRANSLIT', $s2));
}
Это в основном то, что MySql сделает для вас, хотя, вероятно, он быстрее и может иметь несколько другую таблицу сопоставления, чем ISO-8859-1//TRANSLIT
. Не совсем уверен в этом.
Возможно, было бы проще использовать базу данных, как уже предлагали другие.
Я отредактировал вопрос, чтобы точно отразить сопоставление и кодировку для хранения. Не могли бы вы привести мне пример использования mb_string для реализации этого? Я не вижу mb_strcmp в документации.
Я ошибся - нужно использовать iconv, а не mb_string. Я отредактировал свой ответ.
Это приближается. трюк // TRANSLIT хорош, но, как вы упомянули, ISO-8859-1 мне не нужен. MySQL использует сопоставление, которое выглядит примерно так, которое мне нужно как-то подражать: collation-charts.org/mysql60/…
Если довольно ограниченная функциональность Iconv вам не подходит, вы можете попробовать это расширение: derickrethans.nl/translit.php или это (простой php): sitepoint.com/blogs/2006/03/03/…
Оба позволяют использовать базу данных транслитерации, определяемую пользователем. Вы можете скопировать MySqls, если вам нужно точное совпадение. Но, вероятно, было бы проще просто использовать базу данных в первую очередь;)
Также посмотрите на форму нормализации юникода c (iirc). Я недавно сделал это для чего-то на питоне. Он разбивает символ на составные части, после чего вы можете вырезать не-ascci. "<акцент A>" => "A <акцент Unicode>" => "A"
Ссылка на сайт, размещенная @troelskn, сейчас не работает. Вот замена: sitepoint.com/us-ascii-transliterations-of-unicode-text
Итак, если я правильно понял, вы хотите провести такое же сравнение в PHP, как если бы вы проверяли общий индекс UTF-8 в MySQL?
Самым простым было бы создать вспомогательную функцию, которая преобразовывала бы строку в соответствии с правилами utf8_general_ci, используемыми MySSQL, которые в основном предназначены для преобразования определенных букв в базовую букву.
Правила для этого сопоставления MySQL перечислены здесь:
http://www.collation-charts.org/mysql60/mysql604.utf8_general_ci.european.html
Например, если вы прокрутите немного вниз до «золотого А» слева, вы увидите все символы, которые будут преобразованы в этот А.
Учитывая вспомогательную функцию, например, utf8g_to_ascii()
, вы можете написать функцию:
function utf8_compare($s1, $s2) {
$a = utf8g_to_ascii($s1);
$b = utf8g_to_ascii($s2);
return strcmp( $a, $b );
}
Я бы смоделировал свой код после:
http://dev.splitbrain.org/view/darcs/dokuwiki/inc/utf8.php
Используйте подборщик или транслитератор intl.
$s1 = 'a';
$s2 = 'À';
var_dump(
is_same_string($s1, $s2),
$s1 === transliterator_transliterate('Any-Latin; Latin-ASCII; Lower()', $s2)
);
function is_same_string($str, $str2, $locale = 'en_US')
{
$coll = collator_create($locale);
collator_set_strength($coll, Collator::PRIMARY);
return 0 === collator_compare($coll, $str, $str2);
}
Я делаю это с очень большим количеством строк по разным причинам, поэтому я бы не хотел использовать базу данных.