如何在 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 中,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;
【讨论】:
以上是关于如何在 SQLite 查询中忽略重音(Android)的主要内容,如果未能解决你的问题,请参考以下文章
如何忽略 Spring JPA findBy 存储库中的重音符号?