Confrontando le stringhe in PHP allo stesso modo di MySQL
-
19-08-2019 - |
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
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);
}