私は名前や電子メールを検索するとき、それが一致する文字の文字列を表示するように、私のアプリで検索メカニズムを実装しています。しかし、私のリストにあるいくつかのアクセント記号付きの文字列があると私はその特定のアクセントに関連する通常の文字で検索したときに「私は、文字列「アンジェラ」を持っているならば、と言うと、私は、正確な文字列で検索しない限り、「アンジェラ」、それは文字列を表示doesntの検索しますアンジェラ"。
私はそれは関係なく、アクセントの仕事やない、私は「A」、それが「A」と「」とその逆を含むすべての文字列が表示されるはずで入力すると言うことを取得しようとしています。どのようにこれについて移動するために、任意のアイデア?:私は、たとえば、オンラインの記事の束を見上げSQLiteのクエリ(アンドロイド)でアクセントを無視する方法」と、あまりにも正規化しようとしたが、それは部分的に動作しますが、私が検索した場合、 『』、それがaswell通常の文字とアクセント付き文字を示していますが私はアクセント付き文字で検索した場合、それは何も表示さdoesntの。
ここでは、フィルタのための私のコードは次のとおりです。
@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();
}
}
mSearchGuestListResponseListFiltered = filteredList;
}
FilterResults filterResults = new FilterResults();
filterResults.values = mSearchGuestListResponseListFiltered;
return filterResults;
}
@Override
protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
mSearchGuestListResponseListFiltered = (ArrayList<RegisterGuestList.Guest>) filterResults.values;
notifyDataSetChanged();
}
};
}
:ここでは誰もが興味を持っていた場合、全アダプタクラスですhttps://pastebin.com/VxsWWMiSは、ここで対応するアクティビティビューです:
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
mSearchGuestListAdapter.getFilter().filter(query);
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
mSearchGuestListAdapter.getFilter().filter(newText);
mSearchGuestListAdapter.notifyDataSetChanged();
mSearchGuestListAdapter.setFilter(newText);
if(mSearchGuestListAdapter.getItemCount() == 0){
String sourceString = "No match found for <b>" + newText + "</b> ";
mNoMatchTextView.setText(Html.fromHtml(sourceString));
} else {
mEmptyRelativeLayout.setVisibility(View.GONE);
mRecyclerView.setVisibility(View.VISIBLE);
}
return false;
}
});
必要に応じて、任意の詳細を共有することが幸せ。(リストの利用recyclerview)を検索しながらも、ランダムに私はindexoutofboundexception [OnBind]の()メソッドを取得し実行します。
java.lang.IndexOutOfBoundsException: Index: 7, Size: 0
at java.util.ArrayList.get(ArrayList.java:437)
どのようにこれについて移動するために、任意のアイデア?
一般的には、私が使用することをお勧めしますCollator
の強度設定とCollator.PRIMARY
アクセントと変える例を(例えば、含む文字列を比較するために、N
対n
とé
対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;
}
検索対象と同じ長さの各部分は限り照合部に関しては、検索対象と等しいかどうかを、このソース文字列を反復し、チェックします。
たとえば、私たちの元の文字列がある想像してみましょう"This is a Tèst"
、私たちは言葉を捜しています"test"
。この方法は、すべての4文字の部分文字列を反復処理します。
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
とRuleBasedCollationKey
(あなたのプロジェクトでGoogleのグアバを持っていると仮定します):
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);
}