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

我在我的应用程序中实现了一个搜索机制,这样当我搜索姓名或电子邮件时,它会显示具有匹配字符的字符串。但是,我的列表中有一些带重音的字符串,当我使用与该特定重音相关的常规字符进行搜索时,假设我有字符串“à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)

知道该怎么做吗?


翻翻过去那场雪
浏览 95回答 1
1回答

慕少森

一般来说,我建议使用Collator强度设置为 的Collator.PRIMARY来比较包含重音符号和不同大小写的字符串(例如,Nvsn和évs e)。不幸的是,Collator没有contains()功能。所以我们将自己制作。private static boolean contains(String source, String target) {&nbsp; &nbsp; if (target.length() > source.length()) {&nbsp; &nbsp; &nbsp; &nbsp; return false;&nbsp; &nbsp; }&nbsp; &nbsp; Collator collator = Collator.getInstance();&nbsp; &nbsp; collator.setStrength(Collator.PRIMARY);&nbsp; &nbsp; int end = source.length() - target.length() + 1;&nbsp; &nbsp; for (int i = 0; i < end; i++) {&nbsp; &nbsp; &nbsp; &nbsp; String sourceSubstring = source.substring(i, i + target.length());&nbsp; &nbsp; &nbsp; &nbsp; if (collator.compare(sourceSubstring, target) == 0) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return true;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; return false;}这会迭代源字符串,并检查与搜索目标长度相同的每个子字符串是否等于搜索目标(就 Collator 而言)。例如,假设我们的源字符串是,"This is a Tèst"并且我们正在搜索单词"test"。此方法将迭代每个四个字母的子字符串:Thishis&nbsp;is is is&nbsp;is&nbsp;is as a&nbsp;&nbsp;a Ta Tè&nbsp;TèsTèst一旦找到匹配项就会返回 true。由于强度设置为Collator.PRIMARY,整理器认为"Tèst"和"test"相等,因此我们的方法返回true。此方法很可能需要进行更多优化,但这应该是一个合理的起点。编辑RuleBasedCollator:一种可能的优化是利用排序规则键以及and的已知实现细节RuleBasedCollationKey(假设您的项目中有 Google 的 Guava):private static boolean containsBytes(String source, String target) {&nbsp; &nbsp; Collator collator = Collator.getInstance();&nbsp; &nbsp; collator.setStrength(Collator.PRIMARY);&nbsp; &nbsp; byte[] sourceBytes = dropLastFour(collator.getCollationKey(source).toByteArray());&nbsp; &nbsp; byte[] targetBytes = dropLastFour(collator.getCollationKey(target).toByteArray());&nbsp; &nbsp; return Bytes.indexOf(sourceBytes, targetBytes) >= 0;}private static byte[] dropLastFour(byte[] in) {&nbsp; &nbsp; return Arrays.copyOf(in, in.length - 4);}这是相当脆弱的(可能不适用于所有语言环境),但在我的测试中,它的速度快了 2 倍到 10 倍。编辑:要支持突出显示,您应该转换contains()为indexOf(),然后使用该信息:private static int indexOf(String source, String target) {&nbsp; &nbsp; if (target.length() > source.length()) {&nbsp; &nbsp; &nbsp; &nbsp; return -1;&nbsp; &nbsp; }&nbsp; &nbsp; Collator collator = Collator.getInstance();&nbsp; &nbsp; collator.setStrength(Collator.PRIMARY);&nbsp; &nbsp; int end = source.length() - target.length() + 1;&nbsp; &nbsp; for (int i = 0; i < end; i++) {&nbsp; &nbsp; &nbsp; &nbsp; String sourceSubstring = source.substring(i, i + target.length());&nbsp; &nbsp; &nbsp; &nbsp; if (collator.compare(sourceSubstring, target) == 0) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return i;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; return -1;}然后你可以像这样应用它:String guestWholeName = guest.getGuestFirstName() + " " + guest.getGuestLastName();int wholeNameIndex = indexOf(guestWholeName, searchText);if (wholeNameIndex > -1) {&nbsp; &nbsp; Timber.d("guest name first : guest.getGuestFirstName() %s", guest.getGuestFirstName());&nbsp; &nbsp; Timber.d("guest name last : guest.getGuestLastName() %s", guest.getGuestLastName());&nbsp; &nbsp; int endPos = wholeNameIndex + searchText.length();&nbsp; &nbsp; Spannable spannable = new SpannableString(guestWholeName);&nbsp; &nbsp; Typeface firstNameFont = Typeface.createFromAsset(context.getAssets(), "fonts/Graphik-Semibold.otf");&nbsp; &nbsp; spannable.setSpan(new CustomTypefaceSpan("", firstNameFont), wholeNameIndex, endPos, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);&nbsp; &nbsp; Objects.requireNonNull(guestName).setText(spannable);} else {&nbsp; &nbsp; Objects.requireNonNull(guestName).setText(guestWholeName);}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java