Умный поиск контактов в андроиде

Следуя этому руководству по извлечению списка контактов на сайте разработчиков Android, мне удалось реализовать функцию поиска контактов. Вот мой код до сих пор

private void retrieveContactRecord(String phoneNo) {
        try {
            Log.e("Info", "Input: " + phoneNo);
            Uri uri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
                    Uri.encode(phoneNo));
            String[] projection = new String[]{ContactsContract.PhoneLookup._ID, ContactsContract.PhoneLookup.DISPLAY_NAME};


            String sortOrder = ContactsContract.PhoneLookup.DISPLAY_NAME + " COLLATE LOCALIZED ASC";
            ContentResolver cr = getContentResolver();
            if (cr != null) {
                Cursor resultCur = cr.query(uri, projection, null, null, sortOrder);
                if (resultCur != null) {
                    while (resultCur.moveToNext()) {
                        String contactId = resultCur.getString(resultCur.getColumnIndex(ContactsContract.PhoneLookup._ID));
                        String contactName = resultCur.getString(resultCur.getColumnIndexOrThrow(ContactsContract.PhoneLookup.DISPLAY_NAME));
                        Log.e("Info", "Contact Id : " + contactId);
                        Log.e("Info", "Contact Display Name : " + contactName);
                        break;
                    }
                    resultCur.close();
                }
            }
        } catch (Exception sfg) {
            Log.e("Error", "Error in loadContactRecord : " + sfg.toString());
        }
    }

Здесь есть одна загвоздка, этот код работает довольно хорошо, но мне нужно реализовать интеллектуальный поиск здесь. Я хочу, чтобы 26268 соответствовал Amanu, а также 094 526 2684. Я считаю, что это называется словарь T9.

Я попытался посмотреть на другие проекты, но ничего не смог найти. Любые указатели будут оценены!

3 ответа

Решение

ContentProvider для контактов не поддерживает. Так что я сделал, чтобы сбросить все контакты в List затем используйте RegEx соответствовать имени.

public static String[] values = new String[]{" 0", "1", "ABC2", "DEF3", "GHI4", "JKL5", "MNO6", "PQRS7", "TUV8", "WXYZ9"};

/**
 * Get the possible pattern
 * You'll get something like ["2ABC","4GHI"] for input "14"
 */
public static List<String> possibleValues(String in) {

    if (in.length() >= 1) {
        List<String> p = possibleValues(in.substring(1));
        String s = "" + in.charAt(0);
        if (s.matches("[0-9]")) {
            int n = Integer.parseInt(s);

            p.add(0, values[n]);
        } else {
            // It is a character, use it as it is
            p.add(s);
        }

        return p;
    }
    return new ArrayList<>();
}

.... Затем скомпилируйте шаблон. я использовал (?i) чтобы сделать его нечувствительным к регистру

List<String> values = Utils.possibleValues(query);
StringBuilder sb = new StringBuilder();
for (String value : values) {
    sb.append("[");
    sb.append(value);
    sb.append("]");
    if (values.get(values.size() - 1) != value) {
    sb.append("\\s*");
    }
}

Log.e("Utils", "Pattern = " + sb.toString());

Pattern queryPattern = Pattern.compile("(?i)(" + sb.toString() + ")");

Вы будете знать, что делать после этого.

Поиск T9 может быть реализован с использованием структуры данных Trie. Вы можете увидеть пример здесь - Trie dict. После реализации чего-то подобного вы сможете преобразовать ваш поисковый запрос в его возможный декодированный вариант T9 и сравнить, если он совпадает с именем.

Сбросить все контакты в HashSet

Set<String> contacts = new HashSet<String>();

Затем поиск:

List<List<String>> results = new ArrayList<List<String>>();
// start the search, pass empty stack to represent words found so far
search(input, dictionary, new Stack<String>(), results);

Метод поиска ( от @ WhiteFang34)

public static void search(String input, Set<String> contacts,
    Stack<String> words, List<List<String>> results) {

    for (int i = 0; i < input.length(); i++) {
        // take the first i characters of the input and see if it is a word
        String substring = input.substring(0, i + 1);

        if (contacts.contains(substring)) {
            // the beginning of the input matches a word, store on stack
            words.push(substring);

            if (i == input.length() - 1) {
                // there's no input left, copy the words stack to results
                results.add(new ArrayList<String>(words));
            } else {
                // there's more input left, search the remaining part
                search(input.substring(i + 1), contacts, words, results);
            }

            // pop the matched word back off so we can move onto the next i
            words.pop();
        }
    }
}
Другие вопросы по тегам