Utilizzando COLLATE in Android SQLite - Impostazioni internazionali viene ignorato nella dichiarazione COME

StackOverflow https://stackoverflow.com/questions/3480999

Domanda

Quando si crea il mio database SQLite in Android ho impostato il locale del database - db.setLocale (nuova Locale ( "cz_CZ")). Si tratta di un locale Ceca.

lavori istruzione a Selezionare e prende il locale in considerazione, ad esempio:

SELECT * from table WHERE name='sctzy' COLLATE LOCALIZED 

troverete la voce 'ščťžý'.

Ma usando COME fallirà:

SELECT * from table WHERE name LIKE '%sctzy%' COLLATE LOCALIZED 

viene restituito Nessuna riga.

A proposito. Non v'è nessuna classe java.text.Normalized in Android. Ho pensato che avrei potuto fare una seconda colonna con un testo normalizzato, spogliato di caratteri speciali, che sarebbe utilizzato per la ricerca -, ma mi manca una classe o modo per normalizzare la stringa

.
È stato utile?

Soluzione

Hai avuto uno sguardo alla SQLite documentazione per COME ? Si è venuto informazioni sui caratteri non ASCII e un bug. Forse Android ha una vecchia versione di SQLite installato in questo è un problema.

Penso che la seconda colonna normalizzata potrebbe essere la soluzione migliore, purtroppo.

Altri suggerimenti

Creazione di una seconda colonna normalizzato può essere utilizzato per aggirare limitazioni (come brevemente accennato in altre risposte).

In pratica ciò significa che si deve creare un'altra colonna (ombra) del primo in cui gli stessi dati in un caso fisso (ad esempio tutti i caratteri superiori) vengono memorizzati. query insensibili caso (tra cui come query) possono essere fatti su questa nuova colonna con valori di ricerca nello stesso caso.

Se la prima colonna "a" contiene
AAA
AAA
Bbb
AAA
ÉÉÉ
La seconda colonna a_shadow conterrebbe per le stesse righe
AAA
AAA
BBB
AAA
ÉÉÉ

e la vostra query originale (esempio) "selezionare un mytable da dove a = 'AAA'"
sarebbe stato sostituito con "selezionare un mytable da dove A = 'AAA'"

Il codice deve essere aggiornato per riempire il contenuto di ombra convertito quando si aggiunge il contenuto primario. Se si aggiunge la colonna dopo la creazione o non è possibile modificare il codice può avere bisogno di essere convertiti utilizzando una query di aggiornamento dei valori attuali. Esempio:

UPDATE mytable SET a_shadow=UPPER(a);

Proprio oggi ho avuto esattamente lo stesso compito di avere. E nella mia situazione rendendo le colonne d'ombra supplementari non è un caso, perché sto dover cercare più di una colonna. Così sono arrivato alla soluzione di questo tipo, che viene testato in progetto reale. Nel mio caso sto movimentazione solo minuscole ma è possibile estendere la funzione con lettere maiuscole pure.

db.setLocale(Locale("cz", "CZ"))
val query = "SELECT * FROM table WHERE name GLOB ${getExpr(str)} ORDER BY name COLLATE LOCALIZED ASC"

private fun getExpr(input: String) : String{
    var expr = ""
    for(lettter in input){
        expr += when(lettter){
            's','š' -> "[sš]"
            'a','á' -> "[aá]"
            'e','ě','é' -> "[eěé]"
            'i','í' -> "[ií]"
            'z','ž' -> "[zž]"
            'c','č' -> "[cč]"
            'y','ý' -> "[yý]"
            'r','ř' -> "[rř]"
            'u','ů','ú' -> "[uůú]"
            'o','ó' -> "[oó]"
            'n','ň' -> "[nň]"
            'd','ď' -> "[dď]"
            't','ť' -> "[tť]"
            else -> lettter
        }
     }
     return "'*${expr}*'"
}

Potrebbe essere che richiede tempo, ma è possibile utilizzare il java.text.Normalizer come qui

simboli Conversione, Accent Lettere a alfabeto inglese

Dato che non fa parte del sottoinsieme java che Android, si può tentare di cercarlo il codice di Java, come ad esempio Normalizer.java Con il Javadoc trovato qui :

E copiare la parte del codice necessario all'interno del vostro progetto.

La speranza funziona!

In Android SQLite, LIKE e GLOB ignorano sia COLLATE LOCALIZED e COLLATE UNICODE (funzionano solo per ORDER BY). Tuttavia, come spiega in @asat sua risposta , è possibile utilizzare GLOB con un modello che andrà a sostituire ogni lettera con tutte le disponibili alternative di quella lettera. In Java:

public static String addTildeOptions(String searchText) {
    return searchText.toLowerCase()
                     .replaceAll("[aáàäâã]", "\\[aáàäâã\\]")
                     .replaceAll("[eéèëê]", "\\[eéèëê\\]")
                     .replaceAll("[iíìî]", "\\[iíìî\\]")
                     .replaceAll("[oóòöôõ]", "\\[oóòöôõ\\]")
                     .replaceAll("[uúùüû]", "\\[uúùüû\\]")
                     .replace("*", "[*]")
                     .replace("?", "[?]");
}

E poi (non letteralmente come questo, ovviamente):

SELECT * from table WHERE lower(column) GLOB "*addTildeOptions(searchText)*"

In questo modo, ad esempio in spagnolo, una ricerca utente sia per mas o más otterrà la ricerca convertito in m [AAAAAA] s , tornando entrambi i risultati.

E 'importante notare che GLOB ignora COLLATE NOCASE, è per questo che ho convertito tutto in minuscolo, sia nella funzione e nella query. Si noti inoltre che la funzione lower() in SQLite non funziona su caratteri non ASCII - ma ancora una volta questi sono probabilmente quelli che si stanno già sostituendo

La funzione sostituisce anche entrambi i caratteri jolly GLOB, * e ?, con "sfuggito" versioni.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top