Android sqliteで照合を使用する - ロケールは類似のステートメントで無視されます

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

質問

AndroidでSQLiteデータベースを作成するとき、データベースロケール-DB.SetLocale(新しいロケール( "CZ_CZ"))を設定します。これはチェコのロケールです。

Selectステートメントは機能し、ロケールを考慮します。たとえば、

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

エントリ「ščťžý」が見つかります。

しかし、likeを使用すると失敗します:

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

列は返されません。

ところで。 AndroidにはJava.text.Normalizedクラスはありません。検索に使用される特殊文字を削除した正規化されたテキストで2番目の列を作ることができると思いましたが、クラスや文字列を正規化する方法がありません。

役に立ちましたか?

解決

あなたはを見ましたか likeのsqliteドキュメント? ASCII以外のキャラクターとバグに関する情報が生まれました。 Androidには、これが問題になっているSQLiteの古いバージョンがインストールされているのかもしれません。

残念ながら、2番目の正規化された列があなたの最良の選択肢かもしれないと思います。

他のヒント

2番目の正規化された列を作成することは、制限を回避するために使用できます(他の回答で簡単に言及したように)。

これは、実際には、固定ケースの同じデータ(すべてのアッパーチャーなど)が保存される最初の(シャドウ)列を作成する必要があることを意味します。この新しい列で、同じケースの検索値を使用して、ケースの非感受性クエリ(クエリのようなクエリを含む)を作成できます。

最初の列「a」が含まれている場合

AAA
AAA
BBB
äää
ééé

2番目の列a_shadowには同じ行が含まれます

AAA
AAA
BBB
ÄÄÄ
ÉÉÉ

元のクエリ(例)「a = 'äää'からmyTableからAを選択してください」
「myTableからa = 'äää」を選択する「aを選択する」に置き換えられます。

プライマリコンテンツを追加するときに、変換されたシャドウコンテンツを入力するには、コードを更新する必要があります。作成後に列が追加された場合、またはコードを変更できない場合、既存の値を更新クエリを使用して変換する必要があります。例:

UPDATE mytable SET a_shadow=UPPER(a);

ちょうど今日、私はあなたとまったく同じタスクを持っていました。そして、私の状況では、追加の影の列を作ることは、複数の列を検索する必要があるため、当てはまりません。それで、私はこのような解決策に来ました。これは実際のプロジェクトでテストされています。私の場合、私は小文字のみの文字のみを処理していますが、高級文字でも機能を拡張できます。

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}*'"
}

時間がかかるかもしれませんが、こちらのようなjava.text.normalizerを使用できます

シンボルを変換し、アクセント文字が英語のアルファベットへ

AndroidがJavaサブセットの一部ではないので、Javaのコードでそれを探してみるかもしれません。 normalizer.javaJavadocが見つかりました ここ:

プロジェクト内で必要なコードの部分をコピーします。

うまくいくことを願っています!

Android sqliteで、 LIKEGLOB 両方を無視します COLLATE LOCALIZEDCOLLATE UNICODE (彼らはのみ働いています ORDER BY)。ただし、@asatが説明するように 彼の答え, 、使用できます GLOB 各文字をその文字の利用可能なすべての選択肢に置き換えるパターンで。 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("?", "[?]");
}

そして(もちろん、文字通りこのようではありません):

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

このように、たとえばスペイン語では、どちらかを検索しているユーザー マス また Más 検索が変換されます m [aáàäâã] s, 、両方の結果を返します。

それに注意することが重要です GLOB 無視します COLLATE NOCASE, それが、機能とクエリの両方ですべてを小文字に変換した理由です。それにも注意してください lower() SQLiteの関数はASSASCII以外のキャラクターでは機能しませんが、おそらくそれらはおそらくあなたがすでに置き換えているものです!

関数は両方を置き換えます GLOB ワイルドカード、 *?, 、「脱出」バージョンを使用します。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top