باستخدام Collate في Android SQLite - يتم تجاهل الأماكن في مثل البيان

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

سؤال

عند إنشاء قاعدة بيانات SQLite الخاصة بي في Android ، قمت بتعيين لغة قاعدة البيانات - DB.SetLocale (لغة جديدة ("CZ_CZ")). هذه لغة التشيك.

تعمل عبارة SELECT وتأخذ الموقع في الاعتبار ، على سبيل المثال:

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

سيجد إدخال "šťťťý".

لكن استخدام مثل سوف يفشل:

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

لم يتم إرجاع أي صف.

بالمناسبة. لا يوجد فئة java.text.nordized في Android. اعتقدت أنه يمكنني عمل عمود ثانٍ بنص طبيعي ، تم تجريده من الأحرف الخاصة ، والذي سيتم استخدامه للبحث - لكنني أفتقد فئة أو طريقة كيفية تطبيع السلسلة.

هل كانت مفيدة؟

المحلول

هل ألقيت نظرة على وثائق sqlite لمثل؟ لقد جاء معلومات حول الأحرف غير ASCII وخلل. ربما يكون لدى Android إصدار أقدم من SQLite مثبت حيث تكون هذه مشكلة.

أعتقد أن العمود الطبيعي الثاني قد يكون أفضل خيار لك للأسف.

نصائح أخرى

يمكن استخدام إنشاء عمود طبيعي ثانٍ للتجول في القيود (كما هو مذكور لفترة وجيزة في إجابات أخرى).

هذا يعني في الممارسة العملية أنه يتعين عليك إنشاء عمود آخر (ظل) من أولك حيث يتم تخزين نفس البيانات في حالة ثابتة (على سبيل المثال جميع chars العليا). يمكن إجراء استعلامات غير حساسة للحالة (بما في ذلك الاستعلامات مثل) على هذا العمود الجديد مع قيم البحث في نفس الحالة.

إذا كان العمود الأول "A" يحتوي على

AAA
AAA
BBB
äää
ééé

سوف يحتوي العمود الثاني A_SHADOW على نفس الصفوف

AAA
AAA
BBB
ÄÄÄ
ÉÉÉ

واستعلامك الأصلي (مثال) "حدد A من mytable حيث a = 'ää'"
سيتم استبداله بـ "SELECT A From MyTable حيث 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 مثل هنا

تحويل الرموز ، رسائل لهجة إلى الأبجدية الإنجليزية

كما هو ليس جزءًا من مجموعة Java الفرعية التي تعمل بنظام Android ، فقد تحاول البحث عنها على رمز Java ، مثل Normalizer.javaمع جافادوك وجدت هنا:

ونسخ جزء الكود المطلوب داخل مشروعك.

نأمل أن يعمل!

في Android SQLite ، LIKE و GLOB تجاهل كليهما COLLATE LOCALIZED و COLLATE UNICODE (إنهم يعملون فقط من أجل ORDER BY). ومع ذلك ، كما يشرح asat في إجابته, ، يمكنك استخدام GLOB بنمط سيحل محل كل حرف بكل بدائل هذه الرسالة المتاحة. في جافا:

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)*"

بهذه الطريقة ، على سبيل المثال باللغة الإسبانية ، يبحث المستخدم عن أي منهما ماس أو ماس سيحصل على البحث إلى م, ، إرجاع كلا النتائج.

من المهم ملاحظة ذلك GLOB يتجاهل COLLATE NOCASE, ، لهذا السبب قمت بتحويل كل شيء إلى حالة منخفضة في الوظيفة وفي الاستعلام. لاحظ أيضًا أن lower() الوظيفة في SQLite لا تعمل على الشخصيات غير ASCII - ولكن مرة أخرى ، ربما تكون تلك هي تلك التي تحل محلها بالفعل!

تستبدل الوظيفة أيضًا كلاهما GLOB أحرف البرية ، * و ?, ، مع إصدارات "هرب".

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top