package com.netease.nim.uikit.contact.core.query; import android.text.TextUtils; public final class TextSearcher { /** T9 */ private boolean mT9; /** string */ private String mStr; // // string state // /** string index */ private int mIndex; /** eaten state */ private boolean mEaten; // // PinYin state // /** PinYin */ private String mPinyin; /** string index after PinYin */ private int mIndexP; /** PinYin sub index */ private int mIndexSub; /** T9 characters */ private static final char[] T9 = { '2', '2', '2', '3', '3', '3', '4', '4', '4', '5', '5', '5', '6', '6', '6', '7', '7', '7', '7', '8', '8', '8', '9', '9', '9', '9' }; /** searcher */ private static final ThreadLocal<TextSearcher> sSearcher = new ThreadLocal<TextSearcher>() { protected TextSearcher initialValue() { return new TextSearcher(); } }; /** * * @param t9 * @return TextSearcher */ public static final TextSearcher obtain(boolean t9) { TextSearcher searcher = sSearcher.get(); searcher.mT9 = t9; return searcher; } /** * * @param s * @param i */ public final void initialize(String s, int i) { mStr = s; mIndex = i; mEaten = true; mPinyin = null; mIndexP = -1; mIndexSub = -1; } /** * * @return last index */ public final int index() { return mIndex; } /** * * @param eat assuming in lower case or [0-9] * @return eaten */ public final boolean eat(char eat) { // // PinYin // boolean pEaten = false; boolean pEnd = false; // on if (mPinyin != null) { // compare then move pEaten = mPinyin.charAt(mIndexSub++) == eat; pEnd = mIndexSub == mPinyin.length(); // not eaten or reach the end if (!pEaten || pEnd) { // close mPinyin = null; } } // // string // String pinyin = null; boolean eaten = false; // on && in bound if (mEaten && mIndex < mStr.length()) { char chr = mStr.charAt(mIndex); if (mT9) { if ('a' <= chr && chr <= 'z') { eaten = T9[chr - 'a'] == eat; } else if ('A' <= chr && chr <= 'Z') { eaten = T9[chr - 'A'] == eat; } else { eaten = chr == eat; } } else { if ('A' <= chr && chr <= 'Z') { eaten = chr + 'a' - 'A' == eat; } else { eaten = chr == eat; } } // PinYin if (!eaten) { pinyin = mT9 ? PinYin.getPinYinT9(chr) : PinYin.getPinYin(chr); // has if (pinyin != null) { // equals if (pinyin.charAt(0) == eat) { eaten = true; } else { // clear pinyin = null; } } } } // fail if (!pEaten && !eaten) { return false; } // string if (eaten) { // next mIndex++; // PinYin fail if (!pEaten) { // clear mPinyin = null; // setup if (pinyin != null && pinyin.length() > 1) { mPinyin = pinyin; // first has done mIndexSub = 1; // at next mIndexP = mIndex; } } } else { // // PinYin here // // reach the end if (pEnd) { // previous index done eaten = true; mIndex = mIndexP; } } // save last mEaten = eaten; return true; } /** * * @param t9 * @param str * @param query assuming in lower case or [0-9] * @return range array or NULL */ public static final int[] indexOf(boolean t9, String str, String query) { if (TextUtils.isEmpty(str) || TextUtils.isEmpty(query)) { return null; } TextSearcher searcher = TextSearcher.obtain(t9); // move EAT: for (int index = 0; index < str.length(); index++) { searcher.initialize(str, index); for (int subIndex = 0; subIndex < query.length(); subIndex++) { if (!searcher.eat(query.charAt(subIndex))) { // next continue EAT; } } // eaten return new int[] {index, searcher.index()}; } return null; } /** * * @param t9 * @param str * @param query assuming in lower case or [0-9] * @return contains */ public static final boolean contains(boolean t9, String str, String query) { if (TextUtils.isEmpty(str) || TextUtils.isEmpty(query)) { return false; } TextSearcher searcher = TextSearcher.obtain(t9); // move EAT: for (int index = 0; index < str.length(); index++) { searcher.initialize(str, index); for (int subIndex = 0; subIndex < query.length(); subIndex++) { if (!searcher.eat(query.charAt(subIndex))) { // next continue EAT; } } // eaten return true; } return false; } /** * * @param t9 * @param str * @param query assuming in lower case or [0-9] * @return last index or -1 */ public static final int startsWith(boolean t9, String str, String query) { if (TextUtils.isEmpty(str) || TextUtils.isEmpty(query)) { return -1; } TextSearcher searcher = TextSearcher.obtain(t9); searcher.initialize(str, 0); for (int subIndex = 0; subIndex < query.length(); subIndex++) { if (!searcher.eat(query.charAt(subIndex))) { // fail return -1; } } return searcher.index(); } }