Сравняване на низове в PHP по същия начин, както прави MySQL

Съхранявам varchar в utf8 MySQL таблица и използвам 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

person twk    schedule 22.01.2009    source източник


Отговори (5)


Съпоставянето няма нищо общо със съхранението. Трябва да зададете набора от знаци, за да определите кодирането за съхранение. Съпоставянето управлява как трябва да се извършва сравнението и сортирането. Подреждането трябва да е запознато с набора от знаци, но в противен случай няма нищо общо с набора от знаци.

За да отговорите на въпроса си, можете да използвате 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. Не съм съвсем сигурен в това.

Вероятно обаче би било по-лесно да се използва базата данни, както други вече предложиха.

person troelskn    schedule 23.01.2009
comment
Редактирах въпроса, за да отразява точно съпоставката срещу набора от знаци за съхранение. Можете ли да ми дадете пример за използване на mb_string за прилагане на това? Не виждам mb_strcmp в документите. - person twk; 23.01.2009
comment
Направих грешка - трябва да използвате iconv - не mb_string. Редактирах отговора си. - person troelskn; 24.01.2009
comment
Това се приближава. трикът //TRANSLIT е добър, но както споменахте, ISO-8859-1 не е това, от което се нуждая. MySQL използва сортиране, което изглежда така, което ще трябва да емулирам по някакъв начин: collation-charts.org/mysql60/ - person twk; 24.01.2009
comment
Ако доста ограничената функционалност на Iconv не ви устройва, можете да опитате с това разширение: derickrethans.nl/translit. php или това (обикновен php): sitepoint.com/blogs/2006/03/03/ - person troelskn; 25.01.2009
comment
И двете ви позволяват да използвате дефинирана от потребителя база данни за транслитериране. Можете да копирате MySql, ако имате нужда от точно съвпадение. Но вероятно би било по-лесно просто да използвате базата данни на първо място ;) - person troelskn; 25.01.2009
comment
Също така разгледайте unicode форма за нормализиране c (iirc). Наскоро направих това за нещо в Python. Ще разбие героя на неговите съставни части, след което можете да премахнете не-ascci. ‹акцент A› =› A‹уникод акцент› =› A - person Richard Levasseur; 04.02.2009
comment
Връзката към точката на сайта, публикувана от @troelskn, вече не работи. Ето замяната: sitepoint.com/us-ascii-transliterations- of-unicode-text - person Jpsy; 09.10.2012

Защо просто не оставите MySQL да реши дали вече има запис със същия ключ?

Можете да изпълните SELECT заявка, за да попитате дали вече има запис с този атрибут:

SELECT 1
FROM UniTest
WHERE str = "À"

Или просто опитайте да вмъкнете новия запис и да използвате функциите mysql_error () и mysql_errno(), за да видите ако е възникнала грешка.

person Gumbo    schedule 22.01.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));  
        }  
    }  

След това ще трябва да тествате всеки низ символ по символ, за да видите дали а) са еднакви, или ако не, б) са еквивалентни.

person dkretz    schedule 22.01.2009
comment
Правя това с много голям брой низове по много различни причини, така че бих искал да избегна базата данни. - person twk; 29.01.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
person alphadogg    schedule 04.02.2009

Използвайте Collator или Transliterator на 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);
}
person masakielastic    schedule 19.09.2013