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.
Daten vom Typ Word z.B. von Wordsearcher, Decomposer, Ocr_variator, MultiWorder
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
Kursiv dargestellte Parameter sind optional (ggf. mit Angabe der Voreinstellung). Alle anderen Parameter müssen zwingend angegeben werden.
siehe allgemeine Beschreibung des Attendee
siehe allgemeine Beschreibung des Attendee
siehe allgemeine Beschreibung des Dictionary
(Standard: all) siehe allgemeine Beschreibung des Dictionary
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')
# File lib/lingo/attendee/multi_worder.rb, line 114 def control(cmd, param) control_multi(cmd, @mul_dic) end
# 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
# 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
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
# 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