Domanda

Sto memorizzando un varchar in una tabella MySQL utf8 e usando la raccolta utf8_general_ci. Ho un indice univoco sul varchar. Mi piacerebbe fare un confronto di stringhe in PHP che è equivalente a quello che MySQL farà sull'indice.

Un esempio specifico è che vorrei essere in grado di rilevare che "a" è considerato equivalente a "& # 192;" in PHP prima che ciò accada:

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
È stato utile?

Soluzione

Le regole di confronto non hanno nulla a che fare con l'archiviazione. È necessario impostare il set di caratteri per determinare la codifica di archiviazione. Le regole di confronto regolano le modalità di confronto e ordinamento. Le regole di confronto devono essere a conoscenza del set di caratteri, ma per il resto non hanno nulla a che fare con il set di caratteri.

Per rispondere alla tua domanda, puoi usare iconv per tradurre il testo, quindi confrontarlo. Ad esempio:

function compare($s1, $s2) {
  return strcmp(
    iconv('UTF-8', 'ISO-8859-1//TRANSLIT', $s1),
    iconv('UTF-8', 'ISO-8859-1//TRANSLIT', $s2));
}

Questo è fondamentalmente ciò che MySql farà per te, sebbene sia probabilmente più veloce e potrebbe avere una tabella di confronto leggermente diversa da ISO-8859-1 // TRANSLIT . Non ne sono del tutto sicuro.

Probabilmente sarebbe più facile usare il database, come altri hanno già suggerito.

Altri suggerimenti

Perché non lasci che MySQL decida se esiste già un record con la stessa chiave?

Puoi eseguire una query SELECT per chiedere se esiste già un record con questo attributo:

SELECT 1
FROM UniTest
WHERE str = "À"

Oppure prova semplicemente a inserire il nuovo record e ad utilizzare le funzioni mysql_error () e mysql_errno () per vedere se si è verificato un errore.

Sarebbe ragionevole lasciare che MySQL faccia il lavoro, inviando una query a MySQL come:

SELECT CASE WHEN '$a' = '$b' THEN 1 ELSE 0 END


Chiarimento post EDIT:

Potresti iterare una sola volta attraverso l'intero set di caratteri di interesse cartesiano unito a se stesso e costruire una matrice associativa php standard di set di equivalenze.

    for each $char1 in $charset {  
        for each $char2 in $charset {  
            $charmatch[$char1][$char2] = mysqlTestMatch($char1, $char2));  
        }  
    }  

Quindi dovresti testare ogni stringa di carattere per carattere, per vedere se a) sono uguali o, in caso contrario, b) sono equivalenti.

Quindi, se lo capisco correttamente, vuoi fare un confronto simile in PHP come faresti con un controllo su un controllo indice UTF-8 in MySQL?

La cosa più semplice sarebbe creare una funzione di supporto che converta una stringa in base alle regole utf8_general_ci utilizzate da MySSQL, che consiste principalmente nel convertire determinate lettere in una lettera base.

Le regole per quel confronto MySQL sono elencate qui:

http://www.collation-charts.org/mysql60/mysql604.utf8_general_ci.european.html

Ad esempio, se scorri leggermente verso il basso fino a " oro A " a sinistra, vedrai tutti i personaggi che vengono convertiti in quella A.

Data una funzione di supporto, chiamata ad esempio utf8g_to_ascii () , potresti scrivere una funzione:

function utf8_compare($s1, $s2) {
   $a = utf8g_to_ascii($s1);
   $b = utf8g_to_ascii($s2);
   return strcmp( $a, $b );
}

Modellerei il mio codice dopo:

http://dev.splitbrain.org/view/darcs/dokuwiki/inc/utf8.php

Usa Intl's Collator o 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);
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top