在Android中使用的SQLite COLLATE - 区域设置在LIKE语句忽略在Androi

2019-05-12 10:38发布

当创建在我的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 

没有行返回。

BTW。 目前在Android中没有java.text.Normalized类。 我以为我可以做一个标准化文本第二列,剥离的特殊字符,这将被用于搜索 - 但我缺少的一类或方式如何正常化的字符串。

Answer 1:

你有没有看看像SQLite的文档 ? 它已经发生了非ASCII字符和一个错误的信息。 也许Android已经安装的SQLite的旧版本,其中这是一个问题。

我认为第二正规列可能是不幸的是您最好的选择。



Answer 2:

创建第二标准化列可以被用来绕过去限制(在其他的答案简要地提​​及)。

这意味着,你必须在一个固定的情况下,相同的数据(例如,所有的上个字符)的存储位置,以创建第一个的另一个(影子)柱的做法。 不区分大小写的查询(包括像查询)可与搜索值在同一案件中这个新列进行。

如果第一列“的” contains

AAA
AAA
BBB
AAA
EEE

第二列a_shadow将包含相同的行

AAA
AAA
BBB
AAA
EEE

和你的原始查询(例如)“从MYTABLE选择其中a =‘AAA’”
将被替换成“从MYTABLE选择一个,其中A =‘AAA’”

您的代码需要更新将主内容时,以填补所转换的阴影的内容。 如果列在创建后添加,也可以不改变代码的现有值可能需要使用更新查询转换。 例:

UPDATE mytable SET a_shadow=UPPER(a);



Answer 3:

可能是耗时的,但你可以使用java.text.Normalizer喜欢这里

符号转换,雅绅特来函英文字母

至于是不是java的子集的Android,您可以尝试寻找它是java的代码,如部分Normalizer.java用的Javadoc发现这里 :

并复制你的项目中所需的代码的一部分。

希望它的作品!



Answer 4:

就在今天,我有完全一样的任务,你有。 而在我的情况做额外的影子列是不是因为我不必搜索多个列的情况下。 所以,我来到了这样的解决方案,这是在真实的项目进行测试。 在我的情况下,我只处理小写字母,但你可以用大写字母扩展功能以及。

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


Answer 5:

在Android的源码, 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)*"

这种方式,例如在西班牙语中,用户搜索任一MASMÁS将得到的搜索转换成m [AAAAAA] S,返回两个结果。

注意到这一点很重要GLOB忽略COLLATE NOCASE ,这就是为什么我无论是在功能和查询转换一切小写。 还要注意的是lower()在sqlite的功能不会对非ASCII字符的工作-但是这些可能是你已经更换的!

该功能还取代了GLOB通配符*? ,以“逃脱”的版本。



文章来源: Using COLLATE in Android SQLite - Locales is ignored in LIKE statement