为了账号安全,请及时绑定邮箱和手机立即绑定

如何允许在 Android 中使用字符重音进行搜索?

如何允许在 Android 中使用字符重音进行搜索?

翻翻过去那场雪 2023-12-30 15:56:26
我在我的应用程序中实现了一个搜索机制,这样当我搜索姓名或电子邮件时,它会显示具有匹配字符的字符串。但是,我的列表中有一些带重音的字符串,当我使用与该特定重音相关的常规字符进行搜索时,假设我有字符串“àngela”并且我搜索“angela”,它不会显示该字符串,除非我使用确切的字符串“进行搜索”安吉拉”。我试图让它工作,无论重音与否,假设我输入“à”,它应该显示包含“à”和“a”的所有字符串,反之亦然。知道该怎么做吗?我在网上查找了一堆文章,例如:How toignoreaccent in SQLite query (Android) ",也尝试了规范化器,但它部分有效,如果我搜索“a”,它确实也会显示带有常规字母的重音字母,但是如果我用带重音的字母搜索,它不会显示任何内容。这是我的过滤器代码:@Override    public Filter getFilter() {        return new Filter() {            @Override            protected FilterResults performFiltering(CharSequence charSequence) {                String charString = charSequence.toString();                if (charString.isEmpty()) {                    mSearchGuestListResponseListFiltered = mSearchGuestListResponseList;                } else {                    List<RegisterGuestList.Guest> filteredList = new ArrayList<>();                    for (RegisterGuestList.Guest row : mSearchGuestListResponseList) {                        // name match condition. this might differ depending on your requirement                        // here we are looking for name or phone number match                        String firstName = row.getGuestFirstName().toLowerCase();                        String lastName = row.getGuestLastName().toLowerCase();                        String name = firstName + " " +lastName;                        String email = row.getGuestEmail().toLowerCase();                        if ( name.trim().contains(charString.toLowerCase().trim()) ||                                email.trim().contains(charString.toLowerCase().trim())){                            filteredList.add(row);                            searchText = charString.toLowerCase();                        }                    }        };    }如果有人感兴趣,这里是整个适配器类:https://pastebin.com/VxsWWMiS 这是相应的活动视图:如有必要,很乐意分享任何细节。另外,我在搜索时随机得到了indexoutofboundexception onBind()方法(使用recyclerview作为列表):java.lang.IndexOutOfBoundsException: Index: 7, Size: 0        at java.util.ArrayList.get(ArrayList.java:437)知道该怎么做吗?
查看完整描述

1 回答

?
慕少森

TA贡献2019条经验 获得超9个赞

一般来说,我建议使用Collator强度设置为 的Collator.PRIMARY来比较包含重音符号和不同大小写的字符串(例如,Nvsn和évs e)。不幸的是,Collator没有contains()功能。


所以我们将自己制作。


private static boolean contains(String source, String target) {

    if (target.length() > source.length()) {

        return false;

    }


    Collator collator = Collator.getInstance();

    collator.setStrength(Collator.PRIMARY);


    int end = source.length() - target.length() + 1;


    for (int i = 0; i < end; i++) {

        String sourceSubstring = source.substring(i, i + target.length());


        if (collator.compare(sourceSubstring, target) == 0) {

            return true;

        }

    }


    return false;

}

这会迭代源字符串,并检查与搜索目标长度相同的每个子字符串是否等于搜索目标(就 Collator 而言)。


例如,假设我们的源字符串是,"This is a Tèst"并且我们正在搜索单词"test"。此方法将迭代每个四个字母的子字符串:


This

his 

is i

s is

 is 

is a

s a 

 a T

a Tè

 Tès

Tèst

一旦找到匹配项就会返回 true。由于强度设置为Collator.PRIMARY,整理器认为"Tèst"和"test"相等,因此我们的方法返回true。


此方法很可能需要进行更多优化,但这应该是一个合理的起点。


编辑RuleBasedCollator:一种可能的优化是利用排序规则键以及and的已知实现细节RuleBasedCollationKey(假设您的项目中有 Google 的 Guava):


private static boolean containsBytes(String source, String target) {

    Collator collator = Collator.getInstance();

    collator.setStrength(Collator.PRIMARY);


    byte[] sourceBytes = dropLastFour(collator.getCollationKey(source).toByteArray());

    byte[] targetBytes = dropLastFour(collator.getCollationKey(target).toByteArray());


    return Bytes.indexOf(sourceBytes, targetBytes) >= 0;

}


private static byte[] dropLastFour(byte[] in) {

    return Arrays.copyOf(in, in.length - 4);

}

这是相当脆弱的(可能不适用于所有语言环境),但在我的测试中,它的速度快了 2 倍到 10 倍。


编辑:要支持突出显示,您应该转换contains()为indexOf(),然后使用该信息:


private static int indexOf(String source, String target) {

    if (target.length() > source.length()) {

        return -1;

    }


    Collator collator = Collator.getInstance();

    collator.setStrength(Collator.PRIMARY);


    int end = source.length() - target.length() + 1;


    for (int i = 0; i < end; i++) {

        String sourceSubstring = source.substring(i, i + target.length());


        if (collator.compare(sourceSubstring, target) == 0) {

            return i;

        }

    }


    return -1;

}

然后你可以像这样应用它:


String guestWholeName = guest.getGuestFirstName() + " " + guest.getGuestLastName();

int wholeNameIndex = indexOf(guestWholeName, searchText);


if (wholeNameIndex > -1) {

    Timber.d("guest name first : guest.getGuestFirstName() %s", guest.getGuestFirstName());

    Timber.d("guest name last : guest.getGuestLastName() %s", guest.getGuestLastName());


    int endPos = wholeNameIndex + searchText.length();


    Spannable spannable = new SpannableString(guestWholeName);

    Typeface firstNameFont = Typeface.createFromAsset(context.getAssets(), "fonts/Graphik-Semibold.otf");

    spannable.setSpan(new CustomTypefaceSpan("", firstNameFont), wholeNameIndex, endPos, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

    Objects.requireNonNull(guestName).setText(spannable);

} else {

    Objects.requireNonNull(guestName).setText(guestWholeName);

}


查看完整回答
反对 回复 2023-12-30
  • 1 回答
  • 0 关注
  • 42 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信