在 Room SQLite 中查询(不区分大小写)忽略重音

Query in Room SQLite (Insensitive casing) ignoring accents

在我的 Android 应用程序的一部分中,您可以按姓名搜索人员。但我需要即使名字或姓氏写错了(例如没有重音)结果也会显示:

示例:

在数据库中:Pérez Juan、Cooper Sheldon、Pérez Adrian

搜索:佩雷斯

显示:Pérez Juan、Pérez Adrian(来自数据库)

我正在使用 LIKE 执行查询并且它可以覆盖不敏感的大小写,但它不适用于重音,因为我必须写完全相同的字母(有或没有重音),这是我的工作代码:

所以我得到了searchPerson

中使用的变量
String name = searchEditText.getText().toString();
            if (!name.equals("")){
                name = "%" + name + "%";
            }

PersonDao

@Query("SELECT *, lastName || ' ' || name AS FullName\n" +
        "FROM Person\n" +
        "WHERE FullName LIKE :fn\n" +
        "ORDER BY FullName")
LiveData<List<Person>> searchPerson(String fn);

在 Whosebug 上找到了可能的解决方案


为了解决口音问题,我发现 this answer 我尝试实施但没有成功

所以我得到了searchPerson

中使用的变量
String name = searchEditText.getText().toString();
            name = addTildeOptions(name);

addTildeOptions 函数

private String addTildeOptions(String searchText) {
    return searchText.toLowerCase()
            .replaceAll("\[aáàäâã]\.*", "[aáàäâã]")
            .replaceAll("\[eéèëê]\.*", "[eéèëê]")
            .replaceAll("\[iíìî]\.*", "[iíìî]")
            .replaceAll("\[oóòöôõ]\.*", "[oóòöôõ]")
            .replaceAll("\[uúùüû]\.*", "[uúùüû]")
            .replace("*", "[*]")
            .replace("?", "[?]");
}

PersonDao

@Query("SELECT *, lastName || ' ' || name AS FullName\n" +
        "FROM Person\n" +
        "WHERE lower(FullName) GLOB :fn\n" +
        "ORDER BY FullName")
LiveData<List<Person>> searchPerson(String fn);

但是这不会return任何结果,即使我输入一个字母它也不会显示任何内容。

我尝试在获取 EditText 的文本时在开头和结尾添加星号,尝试在我的 PersonDao 查询中输入 addTildeOptions 函数,但没有成功,尝试了一些其他不相关的事情却一直没有结果。

我的代码有什么问题?

较新的查询失败的原因是您将 lower 大小写的字符串传递给 WHERE 子句,并且没有行与这些小写字符串匹配。例如,您的 table 包含“Pérez Juan”,而不是“pérez juan”

addTildeOptions 功能运行正常,但您需要对其进行更改,以将所有纯元音字母和带有变音符(波浪号、重音符、元音变音符等)的元音字母替换为“?”字符,以便查询可以使用 LIKE 或 GLOB 查找行:

String globPersonName(String fn) {
    return fn.replaceAll("[aáàäâã]", "?")
            .replaceAll("[eéèëê]", "?")
            .replaceAll("[iíìî]", "?")
            .replaceAll("[oóòöôõ]", "?")
            .replaceAll("[uúùüû]", "?");
}

然后只需删除 lower 调用并在您的查询中保留 GLOB:

@Query("SELECT *, lastName || ' ' || name AS FullName\n" +
        "FROM Person\n" +
        "WHERE FullName GLOB :fn\n" +
        "ORDER BY FullName")
LiveData<List<Person>> searchPerson(String fn);

因此搜索名称的所有变体形式如下:personDao.searchPerson(globPersonName(fn));

例如,globPersonName("Perez Juan") 将 return P?r?z J??n,您的查询应该找到“Pérez Juan”记录。

使用 GLOB 正是我所需要的。但是,我将其稍微更改为多一点“fine-grained”。例如,@zen_of_kermit 的解决方案也将匹配“Poraz Jaen”;但这不会:

String globPersonName(String fn) {
    return fn.replaceAll("[aáàäâã]", "[aáàäâã]")
            .replaceAll("[eéèëê]", "[eéèëê]")
            .replaceAll("[iíìî]", "[iíìî]")
            .replaceAll("[oóòöôõ]", "[oóòöôõ]")
            .replaceAll("[uúùüû]", "[uúùüû]");
}

这样每个元音都被其各自的正则表达式替换,因此它只匹配每个元音的已知个变体。