class Lingo::Attendee::MultiWorder

Mit der bisher beschriebenen Vorgehensweise werden die durch den Tokenizer erkannten Token aufgelöst und in Words verwandelt und über den Abbreviator und Decomposer auch Spezialfälle behandelt, die einzelne Wörter betreffen. Um jedoch auch Namen wie z.B. John F. Kennedy als Sinneinheit erkennen zu können, muss eine Analyse über mehrere Objekte erfolgen. Dies ist die Hauptaufgabe des MultiWorders. Der MultiWorder analysiert die Teile des Datenstroms, die z.B. durch Satzzeichen oder weiteren Einzelzeichen (z.B. ‘(’) begrenzt sind. Erkannte Mehrwortgruppen werden als zusätzliches Objekt in den Datenstrom mit eingefügt.

Mögliche Verlinkung

Erwartet

Daten vom Typ Word z.B. von Wordsearcher, Decomposer, Ocr_variator, MultiWorder

Erzeugt

Daten vom Typ Word (mit Attribut WA_MULTIWORD). Je erkannter Mehrwortgruppe wird ein zusätzliches Word-Objekt in den Datenstrom eingefügt. Z.B. für Ocr_variator, Sequencer, Noneword_filter, Vector_filter

Parameter

Kursiv dargestellte Parameter sind optional (ggf. mit Angabe der Voreinstellung). Alle anderen Parameter müssen zwingend angegeben werden.

in

siehe allgemeine Beschreibung des Attendee

out

siehe allgemeine Beschreibung des Attendee

source

siehe allgemeine Beschreibung des Dictionary

mode

(Standard: all) siehe allgemeine Beschreibung des Dictionary

Beispiele

Bei der Verarbeitung einer normalen Textdatei mit der Ablaufkonfiguration t1.cfg

meeting:
  attendees:
    - text_reader:   { out: lines, files: '$(files)' }
    - tokenizer:     { in: lines, out: token }
    - abbreviator:   { in: token, out: abbrev, source: 'sys-abk' }
    - word_searcher: { in: abbrev, out: words, source: 'sys-dic' }
    - decomposer:    { in: words, out: comps, source: 'sys-dic' }
    - multi_worder:  { in: comps, out: multi, source: 'sys-mul' }
    - debugger:      { in: multi, prompt: 'out>' }

ergibt die Ausgabe über den Debugger: lingo -c t1 test.txt

out> *FILE('test.txt')
out> <Sein = [(sein/s), (sein/v)]>
out> <Name = [(name/s)]>
out> <ist = [(sein/v)]>
out> <johann van siegen|MUL = [(johann van siegen/m)]>
out> <Johann = [(johann/e)]>
out> <van = [(van/w)]>
out> <Siegen = [(sieg/s), (siegen/v), (siegen/e)]>
out> :./PUNC:
out> *EOL('test.txt')
out> *EOF('test.txt')

Protected Instance Methods

control(cmd, param) click to toggle source
# File lib/lingo/attendee/multi_worder.rb, line 114
def control(cmd, param)
  control_multi(cmd, @mul_dic)
end
init() click to toggle source
# File lib/lingo/attendee/multi_worder.rb, line 79
def init
  # combine lexical variants?

  #

  # false = old behaviour

  # true  = first match

  # 'all' = all matches

  @combine = get_key('combine', false)
  @all     = @combine.is_a?(String) && @combine.downcase == 'all'

  lex_src, lex_mod, d = nil, nil, @lingo.dictionary_config['databases']

  (mul_src = get_array('source')).each { |src|
    s, m = d[src].values_at('use-lex', 'lex-mode')

    if lex_src.nil? || lex_src == s
      lex_src, lex_mod = s, m
    else
      warn "#{self.class}: Dictionaries don't match: #{mul_src.join(',')}"
    end
  }

  lex_src = lex_src.split(SEP_RE)
  lex_mod = get_key('lex-mode', lex_mod || 'first')

  @mul_dic = dictionary(mul_src, get_key('mode', 'all'))
  @lex_dic = dictionary(lex_src, lex_mod)
  @lex_gra = grammar(lex_src, lex_mod)

  @syn_dic = if @combine && has_key?('use-syn')
    dictionary(get_array('use-syn'), get_key('syn-mode', 'all'))
  end

  @expected_tokens_in_buffer, @eof_handling = 3, false
end
process_buffer() click to toggle source
# File lib/lingo/attendee/multi_worder.rb, line 118
def process_buffer
  unless form_at(0) == CHAR_PUNCT
    unless (res = check_multiword_key(3)).empty?
      len = res.map { |r|
        r.is_a?(Lexical) ? r.form.split(' ').size : r[%r^\*(\d+)/, 1].to_i
      }.sort!.reverse!

      unless (max = len.first) > 3
        create_and_forward_multiword(3, res)
        forward_number_of_token(3)
      else
        unless @eof_handling || @buffer.size >= max
          @expected_tokens_in_buffer = max
        else
          forward_number_of_token(len.find { |l|
            r = check_multiword_key(l)
            create_and_forward_multiword(l, r) unless r.empty?
          } || 1)

          @expected_tokens_in_buffer = 3
          process_buffer if process_buffer?
        end
      end

      return
    end

    unless (res = check_multiword_key(2)).empty?
      create_and_forward_multiword(2, res)
      forward_number_of_token(1)
    end
  end

  forward_number_of_token(1, false)
  @expected_tokens_in_buffer = 3
end

Private Instance Methods

check_multiword_key(len) click to toggle source

Prüft einen definiert langen Schlüssel ab Position 0 im Buffer

# File lib/lingo/attendee/multi_worder.rb, line 176
def check_multiword_key(len)
  return [] if valid_tokens_in_buffer < len

  seq = @buffer.map { |obj|
    next [obj] unless obj.is_a?(WordForm)
    next if (form = obj.form) == CHAR_PUNCT

    w = find_word(form, @lex_dic, @lex_gra)
    l = w.lexicals

    (w.attr == WA_COMPOUND ? [l.first] : l.empty? ? [w] : l.dup).tap { |i|
      i.concat(@syn_dic.find_synonyms(w)) if @syn_dic
      i.map! { |j| j.form.downcase }.uniq!
    }
  }

  seq.compact!
  seq.slice!(len..-1)

  if @combine
    [].tap { |mul| seq.shift.product(*seq) { |key|
      mul.concat(@mul_dic.select(key.join(' ')))
      break unless @all_keys || mul.empty?
    } && mul.uniq! }
  else
    @mul_dic.select(seq.map!(&:first).join(' '))
  end
end
create_and_forward_multiword(len, lex) click to toggle source
# File lib/lingo/attendee/multi_worder.rb, line 157
def create_and_forward_multiword(len, lex)
  pos, parts = 0, []

  begin
    if (form = form_at(pos)) == CHAR_PUNCT
      @buffer.delete_at(pos)
      parts[-1] += CHAR_PUNCT
    else
      @buffer[pos].attr = WA_UNKMULPART if @buffer[pos].unknown?
      parts << form
      pos += 1
    end
  end while pos < len

  forward(Word.new_lexicals(parts.join(' '),
    WA_MULTIWORD, lex.select { |l| l.is_a?(Lexical) }))
end