Lucene: как сохранить пробелы и т. Д. При токенизации потока? - PullRequest
1 голос
/ 13 января 2012

Я пытаюсь выполнить «перевод» своего рода потока текста.Более конкретно, мне нужно токенизировать входной поток, найти каждый термин в специализированном словаре и вывести соответствующий «перевод» токена.Однако я также хочу сохранить все исходные пробелы, стоп-слова и т. Д. Из входных данных, чтобы выходные данные форматировались так же, как входные, вместо того, чтобы в конечном итоге быть потоком переводов.Так что, если мой ввод

Term1: Term2 Stopword!Term3 Term4

тогда я хочу, чтобы результат выглядел как

Term1 ': Term2' Stopword!Term3 'Term4'

(где Termi ' - перевод Termi ) вместо простого

Term1' Term2 'Term3 'Term4'

В настоящее время я делаю следующее:

PatternAnalyzer pa = new PatternAnalyzer(Version.LUCENE_31,
                             PatternAnalyzer.WHITESPACE_PATTERN,
                             false, 
                             WordlistLoader.getWordSet(new File(stopWordFilePath)));
TokenStream ts = pa.tokenStream(null, in);
CharTermAttribute charTermAttribute = ts.getAttribute(CharTermAttribute.class);

while (ts.incrementToken()) { // loop over tokens
     String termIn = charTermAttribute.toString(); 
     ...
}

, но это, конечно, теряет все пробелы и т. Д. Как я могу изменить это, чтобы иметь возможностьповторно вставить их в вывод?Большое спасибо!

============ ОБНОВЛЕНИЕ!

Я попытался разбить исходный поток на слова и слова.Вроде нормально работает.Не уверен, что это самый эффективный способ:

public ArrayList splitToWords(String sIn) {</p> <pre><code>if (sIn == null || sIn.length() == 0) { return null; } char[] c = sIn.toCharArray(); ArrayList<Token> list = new ArrayList<Token>(); int tokenStart = 0; boolean curIsLetter = Character.isLetter(c[tokenStart]); for (int pos = tokenStart + 1; pos < c.length; pos++) { boolean newIsLetter = Character.isLetter(c[pos]); if (newIsLetter == curIsLetter) { continue; } TokenType type = TokenType.NONWORD; if (curIsLetter == true) { type = TokenType.WORD; } list.add(new Token(new String(c, tokenStart, pos - tokenStart),type)); tokenStart = pos; curIsLetter = newIsLetter; } TokenType type = TokenType.NONWORD; if (curIsLetter == true) { type = TokenType.WORD; } list.add(new Token(new String(c, tokenStart, c.length - tokenStart),type)); return list;

}

1 Ответ

0 голосов
/ 15 января 2012

Ну, на самом деле он не теряет пробелов, у вас все еще есть исходный текст:)

Так что я думаю, вам следует использовать OffsetAttribute, который содержит startOffset () и endOffset () каждого термина в вашемПервоначальный текст.Это то, что Lucene использует, например, для выделения фрагментов результатов поиска из исходного текста.

Я написал быстрый тест (использует EnglishAnalyzer), чтобы продемонстрировать: Ввод:

Just a test of some ideas. Let's see if it works.

Вывод:

just a test of some idea. let see if it work.

// just for example purposes, not necessarily the most performant.
public void testString() throws Exception {
  String input = "Just a test of some ideas. Let's see if it works.";
  EnglishAnalyzer analyzer = new EnglishAnalyzer(Version.LUCENE_35);
  StringBuilder output = new StringBuilder(input);
  // in some cases, the analyzer will make terms longer or shorter.
  // because of this we must track how much we have adjusted the text so far
  // so that the offsets returned will still work for us via replace()
  int delta = 0;

  TokenStream ts = analyzer.tokenStream("bogus", new StringReader(input));
  CharTermAttribute termAtt = ts.addAttribute(CharTermAttribute.class);
  OffsetAttribute offsetAtt = ts.addAttribute(OffsetAttribute.class);
  ts.reset();
  while (ts.incrementToken()) {
    String term = termAtt.toString();
    int start = offsetAtt.startOffset();
    int end = offsetAtt.endOffset();
    output.replace(delta + start, delta + end, term);
    delta += (term.length() - (end - start));
  }
  ts.close();

System.out.println(output.toString());

}

...