Использование Collate в Android SQLite - локали игнорируются в подобном заявлении

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

Вопрос

При создании моей базы данных SQLite в Android я устанавливаю база данных Locale - DB.SetLocale (новый локаль («CZ_CZ»)). Это чешский язык.

Выбор оператора работает и принимает во внимание локаль, например:

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

Найдет запись 'ščťžý'.

Но использование вроде не удастся:

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

Ни один ряд не возвращается.

КСТАТИ. Нет java.text.nomalized класса в Android. Я подумал, что смогу сделать второй столбец с нормализованным текстом, лишенным специальными символами, который будет использоваться для поиска - но мне не хватает класса или способы нормализации строки.

Это было полезно?

Решение

Вы посмотрели на Документация SQLite для? Это пришло информацию о символах без ASCII и ошибке. Возможно, Android имеет более старую версию SQLite, где это проблема.

Я думаю, что вторая нормализованная колонна может быть вашим лучшим вариантом к сожалению.

Другие советы

Создание второго нормализованного столбца может быть использована для обогащения ограничений (как кратко упоминается в других ответах).

Это означает на практике, что вам необходимо создать другой (тень) столбец вашего первого, где одни те же данные в фиксированном случае (например, все верхние символы) хранятся. Нечувствительные случаи запросов (в том числе подобных запросах) могут быть сделаны на этой новой колонне с значениями поиска в том же случае.

Если первый столбец "A" содержит

ААА
ААА
BBB
äää
ééé

Второй столбец a_shadow будет содержать для тех же рядов

ААА
ААА
BBB
ÄÄÄ
ÉÉÉ

и ваш оригинальный запрос (пример) «Выберите от MyTable, где a = 'Ääää'»
будет заменен на «Выбрать A от 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, например Нормализатор.java.С найден Javadoc здесь:

И скопируйте часть кода, необходимого в вашем проекте.

Надеюсь, что это работает!

В Android SQLite, LIKE и GLOB игнорировать оба COLLATE LOCALIZED и COLLATE 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)*"

Таким образом, например, на испанском языке, пользователь ищет либо мака или мас получит поиск, преобразованный в м [Aáàäâã] s, Возвращая оба результата.

Важно отметить, что GLOB игнорирует COLLATE NOCASE, Вот почему я преобразовал все в нижний регистр как в функции, так и в запросе. Обратите внимание, что lower() Функция в Sqlite не работает на символах без ASCII - но опять же, которые, вероятно, те, которые вы уже заменяете!

Функция также заменяет оба GLOB подстановочные знаки, * и ?, с «сбежавшими» версиями.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top