Структура данных для сопоставления имен в тексте

Я хочу найти имена, на которые есть ссылки в текстовых файлах. У автора может быть произвольное количество имен и титулов. Совпадение будет найдено только в том случае, если все имена совпадают (например, человек по имени «Джон Доу» не соответствует тексту, который содержит только «Джон»

То, как я решил это сейчас, состоит в том, чтобы разделить имена на токены и сохранить первый токен в HashSet со строкой нижнего регистра в качестве ключа. Каждый токен содержит набор следующего по имени токена и так далее.

Это приводит к большому количеству объектов HashSet, которые добавляют накладные расходы. Я предполагаю, что есть лучший способ справиться с этим? Я бы предпочел библиотеку, если это возможно, но все поможет

Я готов перейти на Python, если там есть хорошие решения.


person user1175332    schedule 15.10.2012    source источник
comment
У вас есть небольшой образец текстового файла, чтобы показать нам, пожалуйста?   -  person ilango    schedule 16.10.2012
comment
Не там, где я сейчас. Но подумайте с точки зрения Amazon. На самом деле я буду использовать аналогичный источник для значений поиска (авторов). Данные, которые необходимо сопоставить, — это рецензии на книги и т. д., которые содержат много текста, который меня не интересует.   -  person user1175332    schedule 16.10.2012
comment
Чтобы уточнить, вы хотите, чтобы структура данных эффективно хранила мистера Джона Смита, мистера Джона Доу, доктора Джона Смита, доктора Джона Доу и т. д.?   -  person DNA    schedule 16.10.2012
comment
@ДНК: Да. Это будет структура данных в памяти. Я прочитаю много текста из файла и сопоставлю его. В настоящее время у меня есть нечестивая комбинация HashSets внутри HashSets, но кто-то, должно быть, сделал что-то лучше   -  person user1175332    schedule 16.10.2012


Ответы (2)


Можете ли вы просто использовать регулярное выражение? В зависимости от текстовых файлов вам может понадобиться использовать многострочное сопоставление, как показано ниже.

    Pattern p = Pattern.compile("John\\s+Doe", Pattern.MULTILINE);
    Matcher m = p.matcher("I am looking for John \nDoe, I am.");        
    System.out.println(m.find());

Вы также можете сделать это с помощью утилит командной строки, таких как pcregrep - см. это похожий вопрос.

Обновление: для решения вопроса о хранении имен в структуре с эффективным использованием памяти для хранения связанных строк используется Trie, который может быть полезен - вероятно, существует множество бесплатных реализаций, хотя, насколько мне известно, в стандартных библиотеках Java их нет. См. также этот вопрос, а также этот для некоторых предложений.

person DNA    schedule 15.10.2012
comment
Кажется, вопрос о хранении, а не о разборе. - person 9000; 16.10.2012
comment
Существуют тысячи имен, поэтому регулярное выражение не работает. - person user1175332; 16.10.2012

Насколько я понял вашу проблему, вы должны хранить произвольные списки имен для каждого автора и эффективно их сопоставлять.

Я предполагаю, что вы решили проблему синтаксического анализа имен, удаления несущественных/необязательных частей, таких как «Dr», и сохранения частиц, таких как «von» и «de». Ваше нормализованное имя должно быть последовательностью строк в фиксированном регистре (нижний регистр в порядке, хотя я бы придерживался верхнего регистра или заглавного регистра).

Теперь List<String> или String[] будут работать как ключ к HashMap, содержащему другие детали. Боюсь, это не сработает, так как оба они изменяемы, и я не уверен, что их hashCode() методы подходят для этого случая.

Поэтому я бы придумал что-то вроде этого:

class AuthorName(object) {
  private String[] parts;
  public AuthorName(String... name_parts) {
    assert name_parts.length > 0;
    parts = name_parts;
  }

  @Override
  public int hashCode() {
    // hashCode() that only depends on name parts
    int result = 0;
    for (int i=0; i < parts.length; i+=1) result ^= part.hashCode();
    return result;
  }
}

Map<AuthorName, ...> authors = new HashMap<AuthorName, ...>();
authors.put(new AuthorName('John', 'Doe'), ...);
assert authors.get(new AuthorName('John', 'Doe')) != 0

Это не решает многих возможных проблем, таких как «случайный пользователь Joe», «пользователь Joe R» и «J. R. Пользователь» может быть одним и тем же лицом. Это должно решаться на другом уровне.

Если бы вы изложили свой случай более подробно, с примером или двумя, ответы могли бы быть лучше.

Вас также может заинтересовать способ, которым библиотеки нормализуют имена авторов. Люди используют усложнять схемы для соответствия именам.

person 9000    schedule 15.10.2012
comment
У меня есть набор имен, которые я хочу сопоставить с текстом. Допустим, один из этих текстов является статьей в Википедии: en.wikipedia.org/wiki/Spiderman . Разбирая эту статью, я нахожу соответствие между Питером Паркером и Стэном Ли. - person user1175332; 16.10.2012