Использование COLLATE в Android SQLite - Локали игнорируются в инструкции LIKE - PullRequest
13 голосов
/ 14 августа 2010

При создании базы данных SQLite в Android я установил языковой стандарт базы данных - 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.Я думал, что смогу создать второй столбец с нормализованным текстом, лишенным специальных символов, который будет использоваться для поиска, но мне не хватает класса или способа нормализации строки.

Ответы [ 5 ]

7 голосов
/ 14 августа 2010

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

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

2 голосов
/ 28 ноября 2013

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

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

Если первый столбец «а» содержит AAA ааа Bbb 1012 * aaà * EEE Второй столбец a_shadow будет содержать для тех же строк AAA AAA В 1022 * aaà * EEE

и ваш исходный запрос (пример) "выберите из mytable где a = 'äää'"будет заменен на «выберите из mytable, где A = 'ÄÄÄ'"

Ваш код должен быть обновлен, чтобы заполнить преобразованное теневое содержимое при добавлении основного содержимого.Если столбец добавлен после создания или вы не можете изменить код, существующие значения, возможно, придется преобразовать с помощью запроса на обновление.Пример:

UPDATE mytable SET a_shadow=UPPER(a);

1 голос
/ 29 ноября 2018

Только сегодня у меня было точно такое же задание, как и у вас. И в моей ситуации создание дополнительных теневых столбцов - это не тот случай, потому что мне приходится искать более одного столбца. Поэтому я пришел к такому решению, которое тестируется в реальном проекте. В моем случае я обрабатываю только строчные буквы, но вы также можете расширить функцию заглавными буквами.

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}*'"
}
0 голосов
/ 17 апреля 2019

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

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

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

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

0 голосов
/ 04 мая 2012

Может занять много времени, но вы можете использовать java.text.Normalizer, как здесь

Преобразование символов, букв ударения в английский алфавит

Поскольку Android не является частью java-подмножества, вы можете попробовать найти его в коде java, например Normalizer.java С найденным Javadoc здесь :

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

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

...