lingo 1.8.0 → 1.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. data/ChangeLog +13 -0
  2. data/README +49 -29
  3. data/Rakefile +28 -4
  4. data/TODO +2 -9
  5. data/bin/lingo +24 -0
  6. data/bin/lingoctl +24 -0
  7. data/de/lingo-dic.txt +559 -74
  8. data/info/gpl-hdr.txt +21 -24
  9. data/lib/lingo.rb +83 -112
  10. data/lib/lingo/agenda_item.rb +53 -0
  11. data/lib/lingo/attendee.rb +261 -0
  12. data/lib/lingo/attendee/abbreviator.rb +95 -97
  13. data/lib/lingo/attendee/debugger.rb +94 -93
  14. data/lib/lingo/attendee/decomposer.rb +76 -83
  15. data/lib/lingo/attendee/dehyphenizer.rb +141 -144
  16. data/lib/lingo/attendee/formatter.rb +65 -0
  17. data/lib/lingo/attendee/multi_worder.rb +302 -0
  18. data/lib/lingo/attendee/noneword_filter.rb +89 -84
  19. data/lib/lingo/attendee/object_filter.rb +91 -0
  20. data/lib/lingo/attendee/sequencer.rb +159 -158
  21. data/lib/lingo/attendee/synonymer.rb +81 -84
  22. data/lib/lingo/attendee/text_reader.rb +242 -0
  23. data/lib/lingo/attendee/text_writer.rb +169 -0
  24. data/lib/lingo/attendee/tokenizer.rb +192 -191
  25. data/lib/lingo/attendee/variator.rb +152 -156
  26. data/lib/lingo/attendee/vector_filter.rb +140 -135
  27. data/lib/lingo/attendee/word_searcher.rb +98 -0
  28. data/lib/lingo/buffered_attendee.rb +69 -0
  29. data/lib/lingo/cachable.rb +58 -0
  30. data/lib/lingo/call.rb +72 -0
  31. data/lib/lingo/cli.rb +26 -0
  32. data/lib/lingo/config.rb +23 -26
  33. data/lib/lingo/core_ext.rb +42 -0
  34. data/lib/lingo/ctl.rb +239 -173
  35. data/lib/lingo/database.rb +148 -496
  36. data/lib/lingo/database/crypter.rb +85 -0
  37. data/lib/lingo/database/gdbm_store.rb +49 -0
  38. data/lib/lingo/database/hash_store.rb +67 -0
  39. data/lib/lingo/database/libcdb_store.rb +58 -0
  40. data/lib/lingo/database/sdbm_store.rb +64 -0
  41. data/lib/lingo/database/show_progress.rb +81 -0
  42. data/lib/lingo/database/source.rb +134 -0
  43. data/lib/lingo/database/source/key_value.rb +62 -0
  44. data/lib/lingo/database/source/multi_key.rb +65 -0
  45. data/lib/lingo/database/source/multi_value.rb +65 -0
  46. data/lib/lingo/database/source/single_word.rb +60 -0
  47. data/lib/lingo/database/source/word_class.rb +64 -0
  48. data/lib/lingo/error.rb +122 -0
  49. data/lib/lingo/language.rb +78 -518
  50. data/lib/lingo/language/dictionary.rb +173 -0
  51. data/lib/lingo/language/grammar.rb +211 -0
  52. data/lib/lingo/language/lexical.rb +66 -0
  53. data/lib/lingo/language/lexical_hash.rb +88 -0
  54. data/lib/lingo/language/token.rb +48 -0
  55. data/lib/lingo/language/word.rb +130 -0
  56. data/lib/lingo/language/word_form.rb +83 -0
  57. data/lib/lingo/reportable.rb +59 -0
  58. data/lib/lingo/version.rb +1 -1
  59. data/lingo-all.cfg +14 -10
  60. data/lingo-call.cfg +5 -5
  61. data/lingo.cfg +14 -12
  62. data/lingo.rb +26 -0
  63. data/lir.cfg +13 -9
  64. data/spec/spec_helper.rb +1 -0
  65. data/test.cfg +11 -11
  66. data/test/attendee/ts_abbreviator.rb +0 -6
  67. data/test/attendee/ts_decomposer.rb +0 -6
  68. data/test/attendee/{ts_multiworder.rb → ts_multi_worder.rb} +1 -7
  69. data/test/attendee/ts_noneword_filter.rb +1 -7
  70. data/test/attendee/{ts_objectfilter.rb → ts_object_filter.rb} +1 -7
  71. data/test/attendee/ts_sequencer.rb +0 -6
  72. data/test/attendee/ts_synonymer.rb +0 -6
  73. data/test/attendee/{ts_textreader.rb → ts_text_reader.rb} +1 -7
  74. data/test/attendee/{ts_textwriter.rb → ts_text_writer.rb} +1 -7
  75. data/test/attendee/ts_tokenizer.rb +0 -6
  76. data/test/attendee/ts_variator.rb +0 -6
  77. data/test/attendee/ts_vector_filter.rb +1 -7
  78. data/test/attendee/{ts_wordsearcher.rb → ts_word_searcher.rb} +1 -7
  79. data/test/ref/artikel.non +2 -29
  80. data/test/ref/artikel.seq +13 -8
  81. data/test/ref/artikel.vec +30 -15
  82. data/test/ref/artikel.ven +29 -14
  83. data/test/ref/artikel.ver +58 -43
  84. data/test/ref/lir.csv +146 -145
  85. data/test/ref/lir.non +186 -210
  86. data/test/ref/lir.seq +54 -50
  87. data/test/test_helper.rb +41 -36
  88. data/test/ts_database.rb +12 -11
  89. data/test/ts_language.rb +118 -68
  90. metadata +67 -29
  91. data/lib/lingo/attendee/multiworder.rb +0 -301
  92. data/lib/lingo/attendee/objectfilter.rb +0 -86
  93. data/lib/lingo/attendee/textreader.rb +0 -237
  94. data/lib/lingo/attendee/textwriter.rb +0 -196
  95. data/lib/lingo/attendee/wordsearcher.rb +0 -96
  96. data/lib/lingo/attendees.rb +0 -289
  97. data/lib/lingo/const.rb +0 -131
  98. data/lib/lingo/modules.rb +0 -98
  99. data/lib/lingo/types.rb +0 -285
  100. data/lib/lingo/utilities.rb +0 -40
@@ -1,103 +1,108 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  #--
4
- # LINGO ist ein Indexierungssystem mit Grundformreduktion, Kompositumzerlegung,
5
- # Mehrworterkennung und Relationierung.
6
- #
7
- # Copyright (C) 2005-2007 John Vorhauer
8
- # Copyright (C) 2007-2011 John Vorhauer, Jens Wille
9
- #
10
- # This program is free software; you can redistribute it and/or modify it under
11
- # the terms of the GNU Affero General Public License as published by the Free
12
- # Software Foundation; either version 3 of the License, or (at your option)
13
- # any later version.
14
- #
15
- # This program is distributed in the hope that it will be useful, but WITHOUT
16
- # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17
- # FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
18
- # details.
19
- #
20
- # You should have received a copy of the GNU Affero General Public License along
21
- # with this program; if not, write to the Free Software Foundation, Inc.,
22
- # 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
23
- #
24
- # For more information visit http://www.lex-lingo.de or contact me at
25
- # welcomeATlex-lingoDOTde near 50°55'N+6°55'E.
26
- #
27
- # Lex Lingo rules from here on
4
+ ###############################################################################
5
+ # #
6
+ # Lingo -- A full-featured automatic indexing system #
7
+ # #
8
+ # Copyright (C) 2005-2007 John Vorhauer #
9
+ # Copyright (C) 2007-2012 John Vorhauer, Jens Wille #
10
+ # #
11
+ # Lingo is free software; you can redistribute it and/or modify it under the #
12
+ # terms of the GNU Affero General Public License as published by the Free #
13
+ # Software Foundation; either version 3 of the License, or (at your option) #
14
+ # any later version. #
15
+ # #
16
+ # Lingo is distributed in the hope that it will be useful, but WITHOUT ANY #
17
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS #
18
+ # FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for #
19
+ # more details. #
20
+ # #
21
+ # You should have received a copy of the GNU Affero General Public License #
22
+ # along with Lingo. If not, see <http://www.gnu.org/licenses/>. #
23
+ # #
24
+ ###############################################################################
28
25
  #++
29
26
 
30
27
  class Lingo
31
28
 
32
- # Der Noneword_filter ermöglicht es, alle nicht erkannten Wörter aus dem Datenstrom zu
33
- # selektieren und weiterzuleiten. Im Prinzip werden alle erkannten Wörter gefiltert.
34
- # Bei einem Indexierungslauf können so alle nicht durch den Wordsearcher erkannten Wörter,
35
- # also die, die im Wörterbuch nicht enthalten sind, separat ausgegeben werden und als Grundlage für
36
- # die Wörterbuchpflege dienen.
37
- # Der Noneword_filter ist in einer frühen Entwicklungsphase entstanden. Die gleiche Funktion
38
- # kann auch mit dem universelleren Objectfilter mit dem Ausdruck 'obj.kind_of?(Word) && obj.attr==WA_UNKNOWN'
39
- # durchgeführt werden, mit dem einzigen Unterschied, dass der Noneword_filter nur die Wortform weiterleitet.
40
- # Der Noneword_filter verschluckt ebenfalls alle Kommandos, ausser dem Dateianfang (*FILE) und Ende (*EOF),
41
- # sowie dem LIR-Format-Spezifikum (*RECORD).
42
- #
43
- # *Hinweis* Dieser Attendee sammelt die auszugebenden Daten so lange, bis ein Dateiwechsel oder Record-Wechsel
44
- # angekündigt wird. Erst dann werden alle Daten auf einmal weitergeleitet.
45
- #
46
- # === Mögliche Verlinkung
47
- # Erwartet:: Daten vom Typ *Word*, z.B. von Abbreviator, Wordsearcher, Decomposer, Synonymer, Multiworder, Sequencer
48
- # Erzeugt:: Daten vom Typ *String*, z.B. für Textwriter
49
- #
50
- # === Parameter
51
- # Kursiv dargestellte Parameter sind optional (ggf. mit Angabe der Voreinstellung).
52
- # Alle anderen Parameter müssen zwingend angegeben werden.
53
- # <b>in</b>:: siehe allgemeine Beschreibung des Attendee
54
- # <b>out</b>:: siehe allgemeine Beschreibung des Attendee
55
- #
56
- # === Beispiele
57
- # Bei der Verarbeitung einer normalen Textdatei mit der Ablaufkonfiguration <tt>t1.cfg</tt>
58
- # meeting:
59
- # attendees:
60
- # - textreader: { out: lines, files: '$(files)' }
61
- # - tokenizer: { in: lines, out: token }
62
- # - wordsearcher: { in: token, out: words, source: 'sys-dic' }
63
- # - noneword_filter: { in: words, out: filtr }
64
- # - debugger: { in: filtr, prompt: 'out>' }
65
- # ergibt die Ausgabe über den Debugger: <tt>lingo -c t1 test.txt</tt>
66
- # out> *FILE('test.txt')
67
- # out> "lingo"
68
- # out> *EOF('test.txt')
29
+ class Attendee
69
30
 
70
- class Attendee::Noneword_filter < Attendee
31
+ # Der NonewordFilter ermöglicht es, alle nicht erkannten Wörter aus dem Datenstrom zu
32
+ # selektieren und weiterzuleiten. Im Prinzip werden alle erkannten Wörter gefiltert.
33
+ # Bei einem Indexierungslauf können so alle nicht durch den Wordsearcher erkannten Wörter,
34
+ # also die, die im Wörterbuch nicht enthalten sind, separat ausgegeben werden und als Grundlage für
35
+ # die Wörterbuchpflege dienen.
36
+ # Der NonewordFilter ist in einer frühen Entwicklungsphase entstanden. Die gleiche Funktion
37
+ # kann auch mit dem universelleren Objectfilter mit dem Ausdruck 'obj.kind_of?(Word) && obj.attr==WA_UNKNOWN'
38
+ # durchgeführt werden, mit dem einzigen Unterschied, dass der NonewordFilter nur die Wortform weiterleitet.
39
+ # Der NonewordFilter verschluckt ebenfalls alle Kommandos, ausser dem Dateianfang (*FILE) und Ende (*EOF),
40
+ # sowie dem LIR-Format-Spezifikum (*RECORD).
41
+ #
42
+ # *Hinweis* Dieser Attendee sammelt die auszugebenden Daten so lange, bis ein Dateiwechsel oder Record-Wechsel
43
+ # angekündigt wird. Erst dann werden alle Daten auf einmal weitergeleitet.
44
+ #
45
+ # === Mögliche Verlinkung
46
+ # Erwartet:: Daten vom Typ *Word*, z.B. von Abbreviator, Wordsearcher, Decomposer, Synonymer, Multiworder, Sequencer
47
+ # Erzeugt:: Daten vom Typ *String*, z.B. für Textwriter
48
+ #
49
+ # === Parameter
50
+ # Kursiv dargestellte Parameter sind optional (ggf. mit Angabe der Voreinstellung).
51
+ # Alle anderen Parameter müssen zwingend angegeben werden.
52
+ # <b>in</b>:: siehe allgemeine Beschreibung des Attendee
53
+ # <b>out</b>:: siehe allgemeine Beschreibung des Attendee
54
+ #
55
+ # === Beispiele
56
+ # Bei der Verarbeitung einer normalen Textdatei mit der Ablaufkonfiguration <tt>t1.cfg</tt>
57
+ # meeting:
58
+ # attendees:
59
+ # - text_reader: { out: lines, files: '$(files)' }
60
+ # - tokenizer: { in: lines, out: token }
61
+ # - word_searcher: { in: token, out: words, source: 'sys-dic' }
62
+ # - noneword_filter: { in: words, out: filtr }
63
+ # - debugger: { in: filtr, prompt: 'out>' }
64
+ # ergibt die Ausgabe über den Debugger: <tt>lingo -c t1 test.txt</tt>
65
+ # out> *FILE('test.txt')
66
+ # out> "lingo"
67
+ # out> *EOF('test.txt')
71
68
 
72
- protected
69
+ class NonewordFilter < self
73
70
 
74
- def init
75
- @nonewords = []
76
- end
71
+ protected
77
72
 
78
- # Control behandelt die Kommandos zum Öffnen und Schließen einer Datei.
79
- # Für jede Datei wird ein neuer Satz nicht erkannter Wörter registriert.
80
- def control(cmd, par)
81
- case cmd
82
- when STR_CMD_FILE
83
- @nonewords.clear
84
- when STR_CMD_EOL
85
- deleteCmd
86
- when STR_CMD_RECORD, STR_CMD_EOF
87
- nones = @nonewords.sort.uniq
88
- nones.each { |nw| forward(nw) }
89
- add('Objekte gefiltert', nones.size)
90
- @nonewords.clear
73
+ def init
74
+ @nonewords = []
75
+ end
76
+
77
+ # Control behandelt die Kommandos zum Öffnen und Schließen einer Datei.
78
+ # Für jede Datei wird ein neuer Satz nicht erkannter Wörter registriert.
79
+ def control(cmd, par)
80
+ case cmd
81
+ when STR_CMD_FILE
82
+ @nonewords.clear
83
+ when STR_CMD_EOL
84
+ skip_command
85
+ when STR_CMD_RECORD, STR_CMD_EOF
86
+ nones = @nonewords.sort.uniq
87
+ nones.each(&method(:forward))
88
+ add('Objekte gefiltert', nones.size)
89
+ @nonewords.clear
90
+ end
91
91
  end
92
- end
93
92
 
94
- def process(obj)
95
- if obj.is_a?(Word) && obj.attr==WA_UNKNOWN
96
- inc('Anzahl nicht erkannter Wörter')
97
- @nonewords << obj.form.downcase
93
+ def process(obj)
94
+ if obj.is_a?(Word) && obj.unknown?
95
+ inc('Anzahl nicht erkannter Wörter')
96
+ @nonewords << obj.form.downcase
97
+ end
98
98
  end
99
+
99
100
  end
100
101
 
102
+ # For backwards compatibility.
103
+ Nonewordfilter = NonewordFilter
104
+ Noneword_filter = NonewordFilter
105
+
101
106
  end
102
107
 
103
108
  end
@@ -0,0 +1,91 @@
1
+ # encoding: utf-8
2
+
3
+ #--
4
+ ###############################################################################
5
+ # #
6
+ # Lingo -- A full-featured automatic indexing system #
7
+ # #
8
+ # Copyright (C) 2005-2007 John Vorhauer #
9
+ # Copyright (C) 2007-2012 John Vorhauer, Jens Wille #
10
+ # #
11
+ # Lingo is free software; you can redistribute it and/or modify it under the #
12
+ # terms of the GNU Affero General Public License as published by the Free #
13
+ # Software Foundation; either version 3 of the License, or (at your option) #
14
+ # any later version. #
15
+ # #
16
+ # Lingo is distributed in the hope that it will be useful, but WITHOUT ANY #
17
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS #
18
+ # FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for #
19
+ # more details. #
20
+ # #
21
+ # You should have received a copy of the GNU Affero General Public License #
22
+ # along with Lingo. If not, see <http://www.gnu.org/licenses/>. #
23
+ # #
24
+ ###############################################################################
25
+ #++
26
+
27
+ class Lingo
28
+
29
+ class Attendee
30
+
31
+ # Der ObjectFilter ermöglicht es, beliebige Objekte aus dem Datenstrom herauszufiltern.
32
+ # Um die gewünschten Objekte zu identifizieren, sind ein paar Ruby-Kenntnisse und das Wissen
33
+ # um die Lingo Klassen notwendig. Hier sollen kurz die häufigsten Fälle angesprochen werden:
34
+ #
35
+ # Filtern nach einem bestimmten Typ, z.B. Token oder Word wird beispielsweise durch den Ausdruck
36
+ # 'obj.kind_of?(Word)' ermöglicht. Token und Words haben jeweils ein Attribut +attr+.
37
+ # Bei Token gibt +attr+ an, mit welcher Tokenizer-Regel das Token erkannt wurde. So können z.B.
38
+ # alle numerischen Token mit dem Ausdruck 'obj.kind_of?(Token) && obj.attr=="NUMS"' identifiziert
39
+ # werden. Wie bereits gezeigt, können Bedingungen durch logisches UND (&&) oder ODER (||) verknüpft werden.
40
+ # Das Attribut +form+ kann genutzt werden, um auf den Text eines Objektes zuzugreifen, z.B.
41
+ # 'obj.form=="John"'.
42
+ #
43
+ # === Mögliche Verlinkung
44
+ # Erwartet:: Daten beliebigen Typs von allen Attendees
45
+ # Erzeugt:: Daten, die der als Parameter übergebenen Bedingung entsprechen
46
+ #
47
+ # === Parameter
48
+ # Kursiv dargestellte Parameter sind optional (ggf. mit Angabe der Voreinstellung).
49
+ # Alle anderen Parameter müssen zwingend angegeben werden.
50
+ # <b>in</b>:: siehe allgemeine Beschreibung des Attendee
51
+ # <b>out</b>:: siehe allgemeine Beschreibung des Attendee
52
+ # <b><i>objects</i></b>:: (Standard: true) Gibt einen Ruby-Ausdruck an, der, wenn der Ausdruck
53
+ # als Wahr ausgewertet wird, das Objekt weiterleitet und ansonsten filtert.
54
+ #
55
+ # === Beispiele
56
+ # Bei der Verarbeitung einer normalen Textdatei mit der Ablaufkonfiguration <tt>t1.cfg</tt>
57
+ # meeting:
58
+ # attendees:
59
+ # - text_reader: { out: lines, files: '$(files)' }
60
+ # - tokenizer: { in: lines, out: token }
61
+ # - word_searcher: { in: token, out: words, source: 'sys-dic' }
62
+ # - object_filter: { in: words, out: filtr, objects: 'obj.kind_of?(Word) && obj.lexicals.size>0 && obj.lexicals[0].attr==LA_SUBSTANTIV' }
63
+ # - debugger: { in: filtr, prompt: 'out>' }
64
+ # ergibt die Ausgabe über den Debugger: <tt>lingo -c t1 test.txt</tt>
65
+ # out> *FILE('test.txt')
66
+ # out> <Indexierung = [(indexierung/s)]>
67
+ # out> <Indexierung = [(indexierung/s)]>
68
+ # out> *EOL('test.txt')
69
+ # out> *EOF('test.txt')
70
+
71
+ class ObjectFilter < self
72
+
73
+ protected
74
+
75
+ def init
76
+ @obj_eval = get_key('objects', 'true')
77
+ end
78
+
79
+ def process(obj)
80
+ forward(obj) if eval(@obj_eval)
81
+ end
82
+
83
+ end
84
+
85
+ # For backwards compatibility.
86
+ Objectfilter = ObjectFilter
87
+ Object_filter = ObjectFilter
88
+
89
+ end
90
+
91
+ end
@@ -1,188 +1,189 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  #--
4
- # LINGO ist ein Indexierungssystem mit Grundformreduktion, Kompositumzerlegung,
5
- # Mehrworterkennung und Relationierung.
6
- #
7
- # Copyright (C) 2005-2007 John Vorhauer
8
- # Copyright (C) 2007-2011 John Vorhauer, Jens Wille
9
- #
10
- # This program is free software; you can redistribute it and/or modify it under
11
- # the terms of the GNU Affero General Public License as published by the Free
12
- # Software Foundation; either version 3 of the License, or (at your option)
13
- # any later version.
14
- #
15
- # This program is distributed in the hope that it will be useful, but WITHOUT
16
- # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17
- # FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
18
- # details.
19
- #
20
- # You should have received a copy of the GNU Affero General Public License along
21
- # with this program; if not, write to the Free Software Foundation, Inc.,
22
- # 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
23
- #
24
- # For more information visit http://www.lex-lingo.de or contact me at
25
- # welcomeATlex-lingoDOTde near 50°55'N+6°55'E.
26
- #
27
- # Lex Lingo rules from here on
4
+ ###############################################################################
5
+ # #
6
+ # Lingo -- A full-featured automatic indexing system #
7
+ # #
8
+ # Copyright (C) 2005-2007 John Vorhauer #
9
+ # Copyright (C) 2007-2012 John Vorhauer, Jens Wille #
10
+ # #
11
+ # Lingo is free software; you can redistribute it and/or modify it under the #
12
+ # terms of the GNU Affero General Public License as published by the Free #
13
+ # Software Foundation; either version 3 of the License, or (at your option) #
14
+ # any later version. #
15
+ # #
16
+ # Lingo is distributed in the hope that it will be useful, but WITHOUT ANY #
17
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS #
18
+ # FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for #
19
+ # more details. #
20
+ # #
21
+ # You should have received a copy of the GNU Affero General Public License #
22
+ # along with Lingo. If not, see <http://www.gnu.org/licenses/>. #
23
+ # #
24
+ ###############################################################################
28
25
  #++
29
26
 
30
27
  class Lingo
31
28
 
32
- class WordSequence
33
-
34
- attr_reader :classes, :format, :string
35
-
36
- def initialize(wordclasses, format)
37
- @string = wordclasses.downcase
38
- @classes = @string.split(//)
39
- @format = format
40
- end
29
+ class Attendee
30
+
31
+ # Der Sequencer ist von seiner Funktion her ähnlich dem Multiworder. Der Multiworder
32
+ # nutzt zur Erkennung von Mehrwortgruppen spezielle Wörterbücher, der Sequencer hingegen
33
+ # definierte Folgen von Wortklassen. Mit dem Sequencer können Indexterme generiert werden,
34
+ # die sich über mehrere Wörter erstrecken.
35
+ # Die Textfolge "automatische Indexierung und geniale Indexierung"
36
+ # wird bisher in die Indexterme "automatisch", "Indexierung" und "genial" zerlegt.
37
+ # Über die Konfiguration kann der Sequencer Mehrwortgruppen identifizieren, die
38
+ # z.B. aus einem Adjektiv und einem Substantiv bestehen. Mit der o.g. Textfolge würde
39
+ # dann auch "Indexierung, automatisch" und "Indexierung, genial" als Indexterm erzeugt
40
+ # werden. Welche Wortklassenfolgen erkannt werden sollen und wie die Ausgabe aussehen
41
+ # soll, wird dem Sequencer über seine Konfiguration mitgeteilt.
42
+ #
43
+ # === Mögliche Verlinkung
44
+ # Erwartet:: Daten vom Typ *Word* z.B. von Wordsearcher, Decomposer, Ocr_variator, Multiworder
45
+ # Erzeugt:: Daten vom Typ *Word* (mit Attribut WA_SEQUENCE). 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
46
+ #
47
+ # === Parameter
48
+ # Kursiv dargestellte Parameter sind optional (ggf. mit Angabe der Voreinstellung).
49
+ # Alle anderen Parameter müssen zwingend angegeben werden.
50
+ # <b>in</b>:: siehe allgemeine Beschreibung des Attendee
51
+ # <b>out</b>:: siehe allgemeine Beschreibung des Attendee
52
+ # <b><i>stopper</i></b>:: (Standard: TA_PUNCTUATION, TA_OTHER) Gibt die Begrenzungen an, zwischen
53
+ # denen der Sequencer suchen soll, i.d.R. Satzzeichen und Sonderzeichen,
54
+ # weil sie kaum in einer Mehrwortgruppen vorkommen.
55
+ #
56
+ # === Konfiguration
57
+ # Der Sequencer benötigt zur Identifikation von Mehrwortgruppen Regeln, nach denen er
58
+ # arbeiten soll. Die benötigten Regeln werden nicht als Parameter, sondern in der
59
+ # Sprachkonfiguration hinterlegt, die sich standardmäßig in der Datei
60
+ # <tt>de.lang</tt> befindet (YAML-Format).
61
+ # language:
62
+ # attendees:
63
+ # sequencer:
64
+ # sequences: [ [AS, "2, 1"], [AK, "2, 1"] ]
65
+ # Hiermit werden dem Sequencer zwei Regeln mitgeteilt: Er soll Adjektiv-Substantiv- (AS) und
66
+ # Adjektiv-Kompositum-Folgen (AK) erkennen. Zusätzlich ist angegeben, in welchem Format die
67
+ # dadurch ermittelte Wortfolge ausgegeben werden soll. In diesem Beispiel also zuerst das
68
+ # Substantiv und durch Komma getrennt das Adjektiv.
69
+ #
70
+ # === Beispiele
71
+ # Bei der Verarbeitung einer normalen Textdatei mit der Ablaufkonfiguration <tt>t1.cfg</tt>
72
+ # meeting:
73
+ # attendees:
74
+ # - text_reader: { out: lines, files: '$(files)' }
75
+ # - tokenizer: { in: lines, out: token }
76
+ # - word_searcher: { in: token, out: words, source: 'sys-dic' }
77
+ # - sequencer: { in: words, out: seque }
78
+ # - debugger: { in: seque, prompt: 'out>' }
79
+ # ergibt die Ausgabe über den Debugger: <tt>lingo -c t1 test.txt</tt>
80
+ # out> *FILE('test.txt')
81
+ # out> <Lingo|?>
82
+ # out> <kann = [(koennen/v)]>
83
+ # out> <indexierung, automatisch|SEQ = [(indexierung, automatisch/q)]>
84
+ # out> <automatische = [(automatisch/a)]>
85
+ # out> <Indexierung = [(indexierung/s)]>
86
+ # out> <und = [(und/w)]>
87
+ # out> <indexierung, genial|SEQ = [(indexierung, genial/q)]>
88
+ # out> <geniale = [(genial/a), (genialisch/a)]>
89
+ # out> <Indexierung = [(indexierung/s)]>
90
+ # out> :./PUNC:
91
+ # out> *EOL('test.txt')
92
+ # out> *EOF('test.txt')
93
+
94
+ class Sequencer < BufferedAttendee
95
+
96
+ protected
97
+
98
+ def init
99
+ # Parameter verwerten
100
+ @stopper = get_array('stopper', TA_PUNCTUATION + ',' + TA_OTHER).map(&:upcase)
101
+ @seq_strings = get_key('sequences').map { |e| WordSequence.new(*e) }
102
+
103
+ raise MissingConfigError.new(:sequences) if @seq_strings.empty?
104
+ end
41
105
 
42
- def scan(sequence)
43
- pos = 0
106
+ def control(cmd, par)
107
+ # Jedes Control-Object ist auch Auslöser der Verarbeitung
108
+ process_buffer if [STR_CMD_RECORD, STR_CMD_EOF].include?(cmd)
109
+ end
44
110
 
45
- while pos = sequence.index(string, pos)
46
- yield pos, format.dup, classes
47
- pos += 1
111
+ def process_buffer?
112
+ # start buffer processing when stopper token are found or at unknown words
113
+ item = @buffer.last
114
+ (item.is_a?(WordForm) && @stopper.include?(item.attr.upcase)) ||
115
+ (item.is_a?(Word) && item.unknown?)
48
116
  end
49
- end
50
117
 
51
- end
118
+ def process_buffer
119
+ return if @buffer.empty?
52
120
 
53
- # Der Sequencer ist von seiner Funktion her ähnlich dem Multiworder. Der Multiworder
54
- # nutzt zur Erkennung von Mehrwortgruppen spezielle Wörterbücher, der Sequencer hingegen
55
- # definierte Folgen von Wortklassen. Mit dem Sequencer können Indexterme generiert werden,
56
- # die sich über mehrere Wörter erstrecken.
57
- # Die Textfolge "automatische Indexierung und geniale Indexierung"
58
- # wird bisher in die Indexterme "automatisch", "Indexierung" und "genial" zerlegt.
59
- # Über die Konfiguration kann der Sequencer Mehrwortgruppen identifizieren, die
60
- # z.B. aus einem Adjektiv und einem Substantiv bestehen. Mit der o.g. Textfolge würde
61
- # dann auch "Indexierung, automatisch" und "Indexierung, genial" als Indexterm erzeugt
62
- # werden. Welche Wortklassenfolgen erkannt werden sollen und wie die Ausgabe aussehen
63
- # soll, wird dem Sequencer über seine Konfiguration mitgeteilt.
64
- #
65
- # === Mögliche Verlinkung
66
- # Erwartet:: Daten vom Typ *Word* z.B. von Wordsearcher, Decomposer, Ocr_variator, Multiworder
67
- # Erzeugt:: Daten vom Typ *Word* (mit Attribut WA_SEQUENCE). 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
68
- #
69
- # === Parameter
70
- # Kursiv dargestellte Parameter sind optional (ggf. mit Angabe der Voreinstellung).
71
- # Alle anderen Parameter müssen zwingend angegeben werden.
72
- # <b>in</b>:: siehe allgemeine Beschreibung des Attendee
73
- # <b>out</b>:: siehe allgemeine Beschreibung des Attendee
74
- # <b><i>stopper</i></b>:: (Standard: TA_PUNCTUATION, TA_OTHER) Gibt die Begrenzungen an, zwischen
75
- # denen der Sequencer suchen soll, i.d.R. Satzzeichen und Sonderzeichen,
76
- # weil sie kaum in einer Mehrwortgruppen vorkommen.
77
- #
78
- # === Konfiguration
79
- # Der Sequencer benötigt zur Identifikation von Mehrwortgruppen Regeln, nach denen er
80
- # arbeiten soll. Die benötigten Regeln werden nicht als Parameter, sondern in der
81
- # Sprachkonfiguration hinterlegt, die sich standardmäßig in der Datei
82
- # <tt>de.lang</tt> befindet (YAML-Format).
83
- # language:
84
- # attendees:
85
- # sequencer:
86
- # sequences: [ [AS, "2, 1"], [AK, "2, 1"] ]
87
- # Hiermit werden dem Sequencer zwei Regeln mitgeteilt: Er soll Adjektiv-Substantiv- (AS) und
88
- # Adjektiv-Kompositum-Folgen (AK) erkennen. Zusätzlich ist angegeben, in welchem Format die
89
- # dadurch ermittelte Wortfolge ausgegeben werden soll. In diesem Beispiel also zuerst das
90
- # Substantiv und durch Komma getrennt das Adjektiv.
91
- #
92
- # === Beispiele
93
- # Bei der Verarbeitung einer normalen Textdatei mit der Ablaufkonfiguration <tt>t1.cfg</tt>
94
- # meeting:
95
- # attendees:
96
- # - textreader: { out: lines, files: '$(files)' }
97
- # - tokenizer: { in: lines, out: token }
98
- # - wordsearcher: { in: token, out: words, source: 'sys-dic' }
99
- # - sequencer: { in: words, out: seque }
100
- # - debugger: { in: seque, prompt: 'out>' }
101
- # ergibt die Ausgabe über den Debugger: <tt>lingo -c t1 test.txt</tt>
102
- # out> *FILE('test.txt')
103
- # out> <Lingo|?>
104
- # out> <kann = [(koennen/v)]>
105
- # out> <indexierung, automatisch|SEQ = [(indexierung, automatisch/q)]>
106
- # out> <automatische = [(automatisch/a)]>
107
- # out> <Indexierung = [(indexierung/s)]>
108
- # out> <und = [(und/w)]>
109
- # out> <indexierung, genial|SEQ = [(indexierung, genial/q)]>
110
- # out> <geniale = [(genial/a), (genialisch/a)]>
111
- # out> <Indexierung = [(indexierung/s)]>
112
- # out> :./PUNC:
113
- # out> *EOL('test.txt')
114
- # out> *EOF('test.txt')
115
-
116
- class Attendee::Sequencer < BufferedAttendee
117
-
118
- protected
119
-
120
- def init
121
- # Parameter verwerten
122
- @stopper = get_array('stopper', TA_PUNCTUATION + ',' + TA_OTHER).map { |s| s.upcase }
123
- @seq_strings = get_key('sequences').map { |e| WordSequence.new(*e) }
124
-
125
- forward(STR_CMD_ERR, 'Konfiguration ist leer') if @seq_strings.empty?
126
- end
121
+ unless @buffer.size < 2
122
+ matches = Hash.new { |h, k| h[k] = [] }
127
123
 
128
- def control(cmd, par)
129
- # Jedes Control-Object ist auch Auslöser der Verarbeitung
130
- process_buffer if [STR_CMD_RECORD, STR_CMD_EOF].include?(cmd)
131
- end
124
+ sequences(@buffer.map { |obj|
125
+ obj.is_a?(Word) && !obj.unknown? ? obj.attrs(false) : ['#']
126
+ }).uniq.each { |sequence|
127
+ @seq_strings.each { |wordseq|
128
+ wordseq.scan(sequence) { |pos, form, classes|
129
+ inc('Anzahl erkannter Sequenzen')
132
130
 
133
- def process_buffer?
134
- # start buffer processing when stopper token are found or at unknown words
135
- item = @buffer.last
136
- (item.is_a?(StringA) && @stopper.include?(item.attr.upcase)) ||
137
- (item.is_a?(Word) && item.unknown?)
138
- end
131
+ classes.each_with_index { |wc, index|
132
+ @buffer[pos + index].lexicals.find { |lex|
133
+ form.gsub!(index.succ.to_s, lex.form) if lex.attr == wc
134
+ } or break
135
+ } or next
136
+
137
+ matches[pos] << form
138
+ }
139
+ }
140
+ }
139
141
 
140
- def process_buffer
141
- return if @buffer.empty?
142
+ matches.sort.each { |pos, forms|
143
+ forms.uniq.each { |form|
144
+ deferred_insert(pos, Word.new_lexical(form, WA_SEQUENCE, LA_SEQUENCE))
145
+ }
146
+ }
147
+ end
142
148
 
143
- unless @buffer.size < 2
144
- matches = Hash.new { |h, k| h[k] = [] }
149
+ forward_buffer
150
+ end
145
151
 
146
- sequences(@buffer.map { |obj|
147
- obj.is_a?(Word) && !obj.unknown? ? obj.attrs(false) : ['#']
148
- }).uniq.each { |sequence|
149
- @seq_strings.each { |wordseq|
150
- wordseq.scan(sequence) { |pos, form, classes|
151
- inc('Anzahl erkannter Sequenzen')
152
+ private
152
153
 
153
- classes.each_with_index { |wc, index|
154
- @buffer[pos + index].lexicals.find { |lex|
155
- form.gsub!(index.succ.to_s, lex.form) if lex.attr == wc
156
- } or break
157
- } or next
154
+ def sequences(map)
155
+ res = map.shift
158
156
 
159
- matches[pos] << form
160
- }
161
- }
157
+ map.each { |classes|
158
+ temp = []
159
+ res.each { |wc1| classes.each { |wc2| temp << (wc1 + wc2) } }
160
+ res = temp
162
161
  }
163
162
 
164
- matches.sort.each { |pos, forms|
165
- forms.uniq.each { |form|
166
- deferred_insert(pos, Word.new_lexical(form, WA_SEQUENCE, LA_SEQUENCE))
167
- }
168
- }
163
+ res
169
164
  end
170
165
 
171
- forward_buffer
172
- end
166
+ class WordSequence
173
167
 
174
- private
168
+ attr_reader :classes, :format, :string
175
169
 
176
- def sequences(map)
177
- res = map.shift
170
+ def initialize(wordclasses, format)
171
+ @string = wordclasses.downcase
172
+ @classes = @string.split(//)
173
+ @format = format
174
+ end
178
175
 
179
- map.each { |classes|
180
- temp = []
181
- res.each { |wc1| classes.each { |wc2| temp << (wc1 + wc2) } }
182
- res = temp
183
- }
176
+ def scan(sequence)
177
+ pos = 0
178
+
179
+ while pos = sequence.index(string, pos)
180
+ yield pos, format.dup, classes
181
+ pos += 1
182
+ end
183
+ end
184
+
185
+ end
184
186
 
185
- res
186
187
  end
187
188
 
188
189
  end