13

在 Android 中创建我的 SQLite 数据库时,我设置了数据库区域设置 - db.setLocale(new Locale("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 类。我想我可以用规范化的文本制作第二列,去掉特殊字符,用于搜索 - 但我缺少一个类或如何规范化字符串的方法。

4

5 回答 5

7

你看过LIKE 的 SQLite 文档吗?它提供了有关非 ASCII 字符和错误的信息。也许Android安装了旧版本的SQLite,这是一个问题。

不幸的是,我认为第二个标准化列可能是您的最佳选择。

于 2010-08-13T23:37:06.503 回答
2

创建第二个规范化列可用于绕过限制(如其他答案中简要提到的)。

这意味着在实践中,您必须在第一个列中创建另一个(阴影)列,其中存储固定大小写的相同数据(例如,所有大写字符)。可以使用相同大小写的搜索值对这个新列进行不区分大小写的查询(包括类似查询)。

如果第一列“a”包含

AAA
aaa
Bbb
äää
ééé

第二列 a_shadow 将包含相同的行

AAA
AAA
BBB
ÄÄÄ
ÉÉÉ

并且您的原始查询(示例)“从mytable中选择a ='äää'”
将替换为“从mytable中选择a ='ÄÄÄ'”

添加主要内容时,您的代码需要更新以填充转换后的阴影内容。如果列是在创建后添加的,或者您无法更改代码现有值可能需要使用更新查询进行转换。例子:

UPDATE mytable SET a_shadow=UPPER(a);

于 2013-11-28T09:03:12.330 回答
2

就在今天,我的任务与您完全相同。在我的情况下,制作额外的阴影列不是一种情况,因为我必须搜索多个列。所以我来到了这样的解决方案,该解决方案在实际项目中进行了测试。在我的情况下,我只处理小写字母,但您也可以使用大写字母扩展该功能。

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}*'"
}
于 2018-11-29T09:14:13.710 回答
1

在 Android sqlite 中,LIKE忽略GLOBand 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[aáàäâã]s,并返回两个结果。

重要的是要注意GLOBignores COLLATE NOCASE,这就是为什么我在函数和查询中都将所有内容都转换为小写。另请注意lower(),sqlite 中的函数不适用于非 ASCII 字符 - 但这些可能是您已经替换的字符!

该函数还将GLOB通配符*?, 替换为“转义”版本。

于 2019-04-17T09:40:05.310 回答
0

可能很耗时,但您可以像这里一样使用 java.text.Normalizer

将符号、重音字母转换为英文字母

由于不是 Android 的 java 子集的一部分,您可以尝试在 java 的代码中查找它,例如Normalizer.java使用此处 找到的 Javadoc :

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

希望它有效!

于 2012-05-04T09:22:08.750 回答