如何在SQLite查询中忽略重音(Android)

时间:2013-04-29 15:07:39

标签: android sqlite diacritics

我是Android的新手,我正在使用SQLite进行查询。 我的问题是当我在字符串中使用重音时,例如

  • AAA
  • AAA
  • AAA
  • AAA
  • AAA
  • AAA

如果我这样做:

SELECT * FROM TB_MOVIE WHERE MOVIE_NAME LIKE '%a%' ORDER BY MOVIE_NAME;

回归:

  • AAA
  • aaa(它忽略了其他人)

但如果我这样做:

SELECT * FROM TB_MOVIE WHERE MOVIE_NAME LIKE '%à%' ORDER BY MOVIE_NAME;

回归:

  • ààà(忽略标题“ÀÀÀ”)

我想在SQLite DB中选择字符串而不关心重音和大小写。请帮忙。

4 个答案:

答案 0 :(得分:35)

通常,SQL中的字符串比较由列或表达式COLLATE规则控制。在Android中,只有三个归类序列为pre-defined:BINARY(默认),LOCALIZED和UNICODE。它们都不适合您的用例,遗憾的是,Java API中没有公开用于安装新归类函数的C API。

解决这个问题:

  1. 在表格中添加其他列,例如MOVIE_NAME_ASCII
  2. 在删除重音标记的情况下将值存储到此列中。您可以通过将字符串规范化为Unicode Normal Form D(NFD)并删除非ASCII代码点来删除重音,因为NFD将重音字符粗略地表示为纯ASCII +组合重音符号:

    String asciiName = Normalizer.normalize(unicodeName, Normalizer.Form.NFD)
        .replaceAll("[^\\p{ASCII}]", "");
    
  3. 您的文本是否在此ASCII规范化列上搜索,但显示原始unicode列中的数据。

答案 1 :(得分:0)

您可以使用Android NDK重新编译SQLite源,包括所需的ICU(Unicode的国际组件)。 在这里用俄语解释: http://habrahabr.ru/post/122408/

使用ICU编译带有ICU的SQLilte的过程如下所述:

How to compile sqlite with ICU?

不幸的是,您最终会针对不同的CPU使用不同的APK。

答案 2 :(得分:0)

在Android sqlite中,LIKEGLOB会同时忽略COLLATE LOCALIZEDCOLLATE UNICODE(它们仅适用于ORDER BY)。但是,有一种解决方案而不必在表中添加额外的列。正如@asat在this answer中所解释的那样,您可以将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,这就是为什么我在函数和查询中都将所有内容都转换为小写的原因。还请注意,sqlite中的lower()函数不适用于非ASCII字符-但是同样,这些字符很可能已被您替换!

此功能还用“转义”版本替换了GLOB*这两个?通配符。

答案 3 :(得分:-1)

您需要查看这些内容,而不是重音字符,而是完全不同的字符。您也可以寻找a,b或c。话虽这么说,我会尝试使用正则表达式。它看起来像是:

SELECT * from TB_MOVIE WHERE MOVIE_NAME REGEXP '.*[aAàÀ].*' ORDER BY MOVIE_NAME;