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

Posted

技术标签:

【中文标题】如何在 SQLite 查询中忽略重音(Android)【英文标题】:How to ignore accent in SQLite query (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 中选择字符串而不关心重音和大小写。请帮忙。

【问题讨论】:

Accented Search in sqlite (android)的可能重复 与上述不重复 - 它是关于正确整理重音字符(大写/小写匹配),而不是忽略它们。 【参考方案1】:

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

要解决这个问题:

    在表格中添加另一列,例如MOVIE_NAME_ASCII

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

    String asciiName = Normalizer.normalize(unicodeName, Normalizer.Form.NFD)
        .replaceAll("[^\\pASCII]", "");
    

    在此 ASCII 规范化列上进行文本搜索,但显示原始 unicode 列中的数据。

【讨论】:

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

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

这样,例如在西班牙语中,搜索 masmá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;

【讨论】:

以上是关于如何在 SQLite 查询中忽略重音(Android)的主要内容,如果未能解决你的问题,请参考以下文章

如何搜索忽略重音字符的字符串(例如ã = a)[重复]

如何忽略 Spring JPA findBy 存储库中的重音符号?

SQLite unicode 斯拉夫重音词 Android

如何使用 elasticsearch nest api 创建自定义分析器以忽略重音和 pt-br 停用词?

忽略重音的文本框上的自动完成

OrderBy 忽略重音字母