Сравнивая строки в PHP так же, как MySQL - PullRequest
6 голосов
/ 23 января 2009

Я храню 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

Ответы [ 5 ]

9 голосов
/ 23 января 2009

Сличение не имеет ничего общего с хранилищем. Вам необходимо установить кодировку, чтобы определить кодировку хранилища. Сортировка определяет, как должно происходить сравнение и сортировка. Параметры сортировки должны знать кодировку, но в противном случае они не имеют ничего общего с кодировкой.

Чтобы ответить на ваш вопрос, вы можете использовать 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. Не совсем уверен в этом.

Возможно, было бы проще использовать базу данных, как уже предлагали другие.

1 голос
/ 23 января 2009

Почему бы вам просто не позволить MySQL решить, существует ли уже запись с таким же ключом?

Вы можете выполнить запрос SELECT, чтобы узнать, существует ли уже запись с этим атрибутом:

SELECT 1
FROM UniTest
WHERE str = "À"

Или просто попробуйте вставить новую запись и использовать функции mysql_error () и mysql_errno () , чтобы проверить, произошла ли ошибка.

1 голос
/ 23 января 2009

Было бы разумно просто позволить 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));  
        }  
    }  

Затем вам нужно будет проверить каждую строковый символ за символом, чтобы увидеть, а) совпадают ли они, или если нет, б) они эквивалентны.

0 голосов
/ 19 сентября 2013

Используйте Intl's Collator или Transliterator.

$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);
}
0 голосов
/ 04 февраля 2009

Итак, если я правильно понял, вы хотите сделать аналогичное сравнение в 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
...