【问题标题】:How to ignore accent in SQLite query (Android)如何在 SQLite 查询中忽略重音(Android)
【发布时间】:2013-04-23 07:43:51
【问题描述】:

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

  • ÁÁÁ
  • 咩咩
  • ÀÀÀ
  • ààà
  • 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 中选择字符串而不关心重音和大小写。请帮忙。

【问题讨论】:

标签: android sqlite diacritics


【解决方案1】:

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

要解决这个问题:

  1. 在表格中添加另一列,例如MOVIE_NAME_ASCII
  2. 将值存储到此列中,删除重音符号。您可以通过将字符串规范化为 Unicode 范式 D (NFD) 并删除非 ASCII 代码点来删除重音,因为 NFD 将重音字符大致表示为纯 ASCII + 组合重音标记:

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

【讨论】:

  • 对我也有用,但我想知道是否没有其他方法可以做到这一点
【解决方案2】:

在 Android sqlite 中,LIKE 和 GLOB 忽略 COLLATE LOCALIZED 和 COLLATE 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 通配符* 和? 替换为“转义”版本。

【讨论】:

  • 我必须修复你的正则表达式才能让它工作,因为它是倒置的。 .replaceAll("[aáàäâã]", "\\[aáàäâã\\]")在哪里我不得不使用.replaceAll("\\.*[aáàäâã]\\.*", "[aáàäâã]")
【解决方案3】:

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

这里解释了使用ICU源码编译SQLilte的过程:

How to compile sqlite with ICU?

很遗憾,您最终会得到针对不同 CPU 的不同 APK。

【讨论】:

    【解决方案4】:

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

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

    【讨论】:

      猜你喜欢
      • 2014-04-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-28
      • 2011-10-15
      • 1970-01-01
      相关资源
      最近更新 更多