lingo 1.8.0 → 1.8.1

Sign up to get free protection for your applications and to get access to all the features.
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,216 +1,217 @@
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 Tokenizer zerlegt eine Textzeile in einzelne Token. Dies ist notwendig,
33
- # damit nachfolgende Attendees die Textdatei häppchenweise verarbeiten können.
34
- #
35
- # === Mögliche Verlinkung
36
- # Erwartet:: Daten des Typs *String* (Textzeilen) z.B. von Textreader
37
- # Erzeugt:: Daten des Typs *Token* z.B. für Abbreviator, Wordsearcher
38
- #
39
- # === Parameter
40
- # Kursiv dargestellte Parameter sind optional (ggf. mit Angabe der Voreinstellung).
41
- # Alle anderen Parameter müssen zwingend angegeben werden.
42
- # <b>in</b>:: siehe allgemeine Beschreibung des Attendee.
43
- # <b>out</b>:: siehe allgemeine Beschreibung des Attendee
44
- #
45
- # === Konfiguration
46
- # Der Tokenizer benötigt zur Identifikation einzelner Token Regeln, nach denen er
47
- # arbeiten soll. Die benötigten Regeln werden aufgrund des Umfangs nicht als Parameter,
48
- # sondern in der Sprachkonfiguration hinterlegt, die sich standardmäßig in der Datei
49
- # <tt>de.lang</tt> befindet (YAML-Format).
50
- # language:
51
- # attendees:
52
- # tokenizer:
53
- # regulars:
54
- # - _CHR_: '\wÄÖÜÁÂÀÉÊÈÍÎÌÓÔÒÚÛÙÝäöüáâàéêèíîìóôòúûùý'
55
- # - NUMS: '[+-]?(\d{4,}|\d{1,3}(\.\d{3,3})*)(\.|(,\d+)?%?)'
56
- # - URLS: '((mailto:|(news|http|https|ftp|ftps)://)\S+|^(www(\.\S+)+)|\S+([\._]\S+)+@\S+(\.\S+)+)'
57
- # - ABRV: '(([_CHR_]+\.)+)[_CHR_]+'
58
- # - ABRS: '(([_CHR_]{1,1}\.)+)(?!\.\.)'
59
- # - WORD: '[_CHR_\d]+'
60
- # - PUNC: '[!,\.:;?]'
61
- # - OTHR: '[—„!\"#$%&()*\+,\-\./:;<=>?@\[\\\]^_`{|}~´]'
62
- # - HELP: '.*'
63
- # Die Regeln werden in der angegebenen Reihenfolge abgearbeitet, solange bis ein Token
64
- # erkannt wurde. Sollte keine Regel zutreffen, so greift die letzt Regel +HELP+ in jedem
65
- # Fall.
66
- # Regeln, deren Name in Unterstriche eingefasst sind, werden als Makro interpretiert.
67
- # Makros werden genutzt, um lange oder sich wiederholende Bestandteile von Regeln
68
- # einmalig zu definieren und in den Regeln über den Makronamen eine Auflösung zu forcieren.
69
- # Makros werden selber nicht für die Erkennung von Token eingesetzt.
70
- #
71
- # === Generierte Kommandos
72
- # Damit der nachfolgende Datenstrom einwandfrei verarbeitet werden kann, generiert der Tokenizer
73
- # Kommandos, die mit in den Datenstrom eingefügt werden.
74
- # <b>*EOL(<dateiname>)</b>:: Kennzeichnet das Ende einer Textzeile, da die Information ansonsten
75
- # für nachfolgende Attendees verloren wäre.
76
- #
77
- # === Beispiele
78
- # Bei der Verarbeitung einer normalen Textdatei mit der Ablaufkonfiguration <tt>t1.cfg</tt>
79
- # meeting:
80
- # attendees:
81
- # - textreader: { out: lines, files: '$(files)' }
82
- # - tokenizer: { in: lines, out: token }
83
- # - debugger: { in: token, prompt: 'out>' }
84
- # ergibt die Ausgabe über den Debugger: <tt>lingo -c t1 test.txt</tt>
85
- # out> *FILE('test.txt')
86
- # out> :Dies/WORD:
87
- # out> :ist/WORD:
88
- # out> :eine/WORD:
89
- # out> :Zeile/WORD:
90
- # out> :./PUNC:
91
- # out> *EOL('test.txt')
92
- # out> :Dies/WORD:
93
- # out> :ist/WORD:
94
- # out> :noch/WORD:
95
- # out> :eine/WORD:
96
- # out> :./PUNC:
97
- # out> *EOL('test.txt')
98
- # out> *EOF('test.txt')
99
-
100
- class Attendee::Tokenizer < Attendee
101
-
102
- protected
103
-
104
- def init
105
- # Regular Expressions für Token-Erkennung einlesen
106
- regulars = get_key('regulars', '')
107
- forward(STR_CMD_ERR, 'regulars nicht definiert') unless regulars
108
-
109
- @space = get_key('space', false)
110
- @tags = get_key('tags', true)
111
- @wiki = get_key('wiki', true)
112
-
113
- # default rules
114
- @rules = [['SPAC', /^\s+/]]
115
- @rules << ['HTML', /^<[^>]+>/] unless @tags
116
- @rules << ['WIKI', /^\[\[.+?\]\]/] unless @wiki
117
- @rules.unshift(['WIKI', /^=+.+=+$/]) unless @wiki
118
-
119
- # Mit _xxx_ gekennzeichnete Makros anwenden und Expressions ergänzen und umwandeln
120
- macros = {}
121
-
122
- regulars.each { |rule|
123
- name = rule.keys[0]
124
- expr = rule.values[0].gsub(/_(\w+?)_/) {
125
- macros[$&] || begin
126
- Lingo.const_get("UTF_8_#{$1.upcase}")
127
- rescue NameError
29
+ class Attendee
30
+
31
+ # Der Tokenizer zerlegt eine Textzeile in einzelne Token. Dies ist notwendig,
32
+ # damit nachfolgende Attendees die Textdatei häppchenweise verarbeiten können.
33
+ #
34
+ # === Mögliche Verlinkung
35
+ # Erwartet:: Daten des Typs *String* (Textzeilen) z.B. von TextReader
36
+ # Erzeugt:: Daten des Typs *Token* z.B. für Abbreviator, Wordsearcher
37
+ #
38
+ # === Parameter
39
+ # Kursiv dargestellte Parameter sind optional (ggf. mit Angabe der Voreinstellung).
40
+ # Alle anderen Parameter müssen zwingend angegeben werden.
41
+ # <b>in</b>:: siehe allgemeine Beschreibung des Attendee.
42
+ # <b>out</b>:: siehe allgemeine Beschreibung des Attendee
43
+ #
44
+ # === Konfiguration
45
+ # Der Tokenizer benötigt zur Identifikation einzelner Token Regeln, nach denen er
46
+ # arbeiten soll. Die benötigten Regeln werden aufgrund des Umfangs nicht als Parameter,
47
+ # sondern in der Sprachkonfiguration hinterlegt, die sich standardmäßig in der Datei
48
+ # <tt>de.lang</tt> befindet (YAML-Format).
49
+ # language:
50
+ # attendees:
51
+ # tokenizer:
52
+ # regulars:
53
+ # - _CHR_: '\wÄÖÜÁÂÀÉÊÈÍÎÌÓÔÒÚÛÙÝäöüáâàéêèíîìóôòúûùý'
54
+ # - NUMS: '[+-]?(\d{4,}|\d{1,3}(\.\d{3,3})*)(\.|(,\d+)?%?)'
55
+ # - URLS: '((mailto:|(news|http|https|ftp|ftps)://)\S+|^(www(\.\S+)+)|\S+([\._]\S+)+@\S+(\.\S+)+)'
56
+ # - ABRV: '(([_CHR_]+\.)+)[_CHR_]+'
57
+ # - ABRS: '(([_CHR_]{1,1}\.)+)(?!\.\.)'
58
+ # - WORD: '[_CHR_\d]+'
59
+ # - PUNC: '[!,\.:;?]'
60
+ # - OTHR: '[—„!\"#$%&()*\+,\-\./:;<=>?@\[\\\]^_`{|}~´]'
61
+ # - HELP: '.*'
62
+ # Die Regeln werden in der angegebenen Reihenfolge abgearbeitet, solange bis ein Token
63
+ # erkannt wurde. Sollte keine Regel zutreffen, so greift die letzt Regel +HELP+ in jedem
64
+ # Fall.
65
+ # Regeln, deren Name in Unterstriche eingefasst sind, werden als Makro interpretiert.
66
+ # Makros werden genutzt, um lange oder sich wiederholende Bestandteile von Regeln
67
+ # einmalig zu definieren und in den Regeln über den Makronamen eine Auflösung zu forcieren.
68
+ # Makros werden selber nicht für die Erkennung von Token eingesetzt.
69
+ #
70
+ # === Generierte Kommandos
71
+ # Damit der nachfolgende Datenstrom einwandfrei verarbeitet werden kann, generiert der Tokenizer
72
+ # Kommandos, die mit in den Datenstrom eingefügt werden.
73
+ # <b>*EOL(<dateiname>)</b>:: Kennzeichnet das Ende einer Textzeile, da die Information ansonsten
74
+ # für nachfolgende Attendees verloren wäre.
75
+ #
76
+ # === Beispiele
77
+ # Bei der Verarbeitung einer normalen Textdatei mit der Ablaufkonfiguration <tt>t1.cfg</tt>
78
+ # meeting:
79
+ # attendees:
80
+ # - text_reader: { out: lines, files: '$(files)' }
81
+ # - tokenizer: { in: lines, out: token }
82
+ # - debugger: { in: token, prompt: 'out>' }
83
+ # ergibt die Ausgabe über den Debugger: <tt>lingo -c t1 test.txt</tt>
84
+ # out> *FILE('test.txt')
85
+ # out> :Dies/WORD:
86
+ # out> :ist/WORD:
87
+ # out> :eine/WORD:
88
+ # out> :Zeile/WORD:
89
+ # out> :./PUNC:
90
+ # out> *EOL('test.txt')
91
+ # out> :Dies/WORD:
92
+ # out> :ist/WORD:
93
+ # out> :noch/WORD:
94
+ # out> :eine/WORD:
95
+ # out> :./PUNC:
96
+ # out> *EOL('test.txt')
97
+ # out> *EOF('test.txt')
98
+
99
+ class Tokenizer < self
100
+
101
+ protected
102
+
103
+ def init
104
+ # Regular Expressions für Token-Erkennung einlesen
105
+ regulars = get_key('regulars', '')
106
+ raise NoConfigKeyError.new(:regulars) unless regulars
107
+
108
+ @space = get_key('space', false)
109
+ @tags = get_key('tags', true)
110
+ @wiki = get_key('wiki', true)
111
+
112
+ # default rules
113
+ @rules = [['SPAC', /^\s+/]]
114
+ @rules << ['HTML', /^<[^>]+>/] unless @tags
115
+ @rules << ['WIKI', /^\[\[.+?\]\]/] unless @wiki
116
+ @rules.unshift(['WIKI', /^=+.+=+$/]) unless @wiki
117
+
118
+ # Mit _xxx_ gekennzeichnete Makros anwenden und Expressions ergänzen und umwandeln
119
+ macros = {}
120
+
121
+ regulars.each { |rule|
122
+ name = rule.keys[0]
123
+ expr = rule.values[0].gsub(/_(\w+?)_/) {
124
+ macros[$&] || begin
125
+ Database::Source.const_get("UTF8_#{$1.upcase}")
126
+ rescue NameError
127
+ end
128
+ }
129
+
130
+ if name =~ /^_\w+_$/ # is a macro
131
+ macros[name] = expr if name =~ /^_\w+_$/
132
+ else
133
+ @rules << [name, Regexp.new('^'+expr)]
128
134
  end
129
135
  }
130
136
 
131
- if name =~ /^_\w+_$/ # is a macro
132
- macros[name] = expr if name =~ /^_\w+_$/
133
- else
134
- @rules << [name, Regexp.new('^'+expr)]
135
- end
136
- }
137
-
138
- # Der Tokenizer gibt jedes Zeilenende als Information weiter, sofern es sich
139
- # nicht um die Verarbeitung einer LIR-Datei handelt. Im Falle einer normalen Datei
140
- # wird der Dateiname gespeichert und als Kennzeichen für die Erzeugung von
141
- # Zeilenende-Nachrichten herangezogen.
142
- @filename = nil
143
- end
137
+ # Der Tokenizer gibt jedes Zeilenende als Information weiter, sofern es sich
138
+ # nicht um die Verarbeitung einer LIR-Datei handelt. Im Falle einer normalen Datei
139
+ # wird der Dateiname gespeichert und als Kennzeichen für die Erzeugung von
140
+ # Zeilenende-Nachrichten herangezogen.
141
+ @filename = nil
142
+ end
144
143
 
145
- def control(cmd, param)
146
- case cmd
147
- when STR_CMD_FILE then @filename = param
148
- when STR_CMD_LIR then @filename = nil
149
- when STR_CMD_EOF then @cont = nil
144
+ def control(cmd, param)
145
+ case cmd
146
+ when STR_CMD_FILE then @filename = param
147
+ when STR_CMD_LIR then @filename = nil
148
+ when STR_CMD_EOF then @cont = nil
149
+ end
150
150
  end
151
- end
152
151
 
153
- def process(obj)
154
- if obj.is_a?(String)
155
- inc('Anzahl Zeilen')
152
+ def process(obj)
153
+ if obj.is_a?(String)
154
+ inc('Anzahl Zeilen')
156
155
 
157
- tokenize(obj) { |form, attr|
158
- token = Token.new(form, attr)
156
+ tokenize(obj) { |form, attr|
157
+ token = Token.new(form, attr)
159
158
 
160
- inc('Anzahl Muster '+token.attr)
161
- inc('Anzahl Token')
159
+ inc('Anzahl Muster '+token.attr)
160
+ inc('Anzahl Token')
162
161
 
163
- forward(token)
164
- }
162
+ forward(token)
163
+ }
165
164
 
166
- forward(STR_CMD_EOL, @filename) if @filename
167
- else
168
- forward(obj)
165
+ forward(STR_CMD_EOL, @filename) if @filename
166
+ else
167
+ forward(obj)
168
+ end
169
169
  end
170
- end
171
170
 
172
- private
173
-
174
- # tokenize("Eine Zeile.") -> [:Eine/WORD:, :Zeile/WORD:, :./PUNC:]
175
- def tokenize(textline)
176
- case @cont
177
- when 'HTML'
178
- if textline =~ /^[^<>]*>/
179
- yield $~[0], @cont
180
- textline, @cont = $', nil
181
- else
182
- yield textline, @cont
183
- return
184
- end
185
- when 'WIKI'
186
- if textline =~ /^[^\[\]]*\]\]/
187
- yield $~[0], @cont
188
- textline, @cont = $', nil
189
- else
190
- yield textline, @cont
191
- return
192
- end
193
- when nil
194
- if !@tags && textline =~ /<[^<>]*$/
195
- yield $~[0], @cont = 'HTML'
196
- textline = $`
197
- end
171
+ private
172
+
173
+ # tokenize("Eine Zeile.") -> [:Eine/WORD:, :Zeile/WORD:, :./PUNC:]
174
+ def tokenize(textline)
175
+ case @cont
176
+ when 'HTML'
177
+ if textline =~ /^[^<>]*>/
178
+ yield $~[0], @cont
179
+ textline, @cont = $', nil
180
+ else
181
+ yield textline, @cont
182
+ return
183
+ end
184
+ when 'WIKI'
185
+ if textline =~ /^[^\[\]]*\]\]/
186
+ yield $~[0], @cont
187
+ textline, @cont = $', nil
188
+ else
189
+ yield textline, @cont
190
+ return
191
+ end
192
+ when nil
193
+ if !@tags && textline =~ /<[^<>]*$/
194
+ yield $~[0], @cont = 'HTML'
195
+ textline = $`
196
+ end
197
+
198
+ if !@wiki && textline =~ /\[\[[^\[\]]*$/
199
+ yield $~[0], @cont = 'WIKI'
200
+ textline = $`
201
+ end
202
+ end
198
203
 
199
- if !@wiki && textline =~ /\[\[[^\[\]]*$/
200
- yield $~[0], @cont = 'WIKI'
201
- textline = $`
202
- end
204
+ until textline.empty?
205
+ @rules.each { |name, expr|
206
+ if textline =~ expr
207
+ yield $~[0], name if name != 'SPAC' || @space
208
+ textline = $'
209
+ break
210
+ end
211
+ }
212
+ end
203
213
  end
204
214
 
205
- until textline.empty?
206
- @rules.each { |name, expr|
207
- if textline =~ expr
208
- yield $~[0], name if name != 'SPAC' || @space
209
- textline = $'
210
- break
211
- end
212
- }
213
- end
214
215
  end
215
216
 
216
217
  end
@@ -1,183 +1,179 @@
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 Variator ermöglicht bei nicht erkannten Wörtern den listenbasierten
33
- # Austausch einzelner Wortteile einchließlich erneuter Wörterbuchsuche zur
34
- # Verbesserung der Worterkennungsquote.
35
- #
36
- # Ursprünglich wurde der Variator entwickelt, um die mangelnde Qualität bei der
37
- # OCR-Erkennung altdeutscher 's'-Konsonanten zu optimieren. Er kann ebenso bei
38
- # alternativen Umlautschreibweisen z.B. zur Wandlung von 'Koeln' in 'Köln' dienen.
39
- #
40
- # === Mögliche Verlinkung
41
- # Erwartet:: Daten vom Typ *Word* (andere werden einfach durchgereicht) z.B. von Wordsearcher
42
- # Erzeugt:: Daten vom Typ *Word* zur Weiterleitung z.B. an Synonymer, Decomposer, Multiworder, Sequencer, Noneword_filter oder Vector_filter
43
- #
44
- # === Parameter
45
- # Kursiv dargestellte Parameter sind optional (ggf. mit Angabe der Voreinstellung).
46
- # Alle anderen Parameter müssen zwingend angegeben werden.
47
- # <b>in</b>:: siehe allgemeine Beschreibung des Attendee
48
- # <b>out</b>:: siehe allgemeine Beschreibung des Attendee
49
- # <b>source</b>:: siehe allgemeine Beschreibung des Dictionary
50
- # <b><i>mode</i></b>:: (Standard: all) siehe allgemeine Beschreibung des Dictionary
51
- # <b><i>^check</i></b>:: (Standard: WA_UNKNOWN) Gebrenzt die zu variierenden Worttypen
52
- # <b><i>marker</i></b>:: (Standard: '*') Kennzeichnung durch Variation erkannter Wörter
53
- # <b><i>max-var</i></b>:: (Standard: '10000') Begrenzung der maximal zu prüfenden Permutationen bei der vollständigen Kombination aller auf ein Wort anzuwendenen aufgelisteten Wortteile.
54
- #
55
- # === Beispiele
56
- # Bei der Verarbeitung einer normalen Textdatei mit der Ablaufkonfiguration <tt>t1.cfg</tt>
57
- # meeting:
58
- # attendees:
59
- # - textreader: { out: lines, files: '$(files)' }
60
- # - tokenizer: { in: lines, out: token }
61
- # - wordsearcher: { in: abbrev, out: words, source: 'sys-dic' }
62
- # - variator: { in: words, out: varios, source: 'sys-dic' }
63
- # - debugger: { in: varios, prompt: 'out>' }
64
- # ergibt die Ausgabe über den Debugger: <tt>lingo -c t1 test.txt</tt>
65
- # out> *FILE('test.txt')
66
- # out> <*Dies = [(dies/w)]>
67
- # out> <*ist = [(ist/t)]>
68
- # out> <ein = [(ein/t)]>
69
- # out> <*Tisch = [(tisch/s)]>
70
- # out> :./PUNC:
71
- # out> *EOL('test.txt')
72
- # out> *EOF('test.txt')
73
-
74
- class Attendee::Variator < Attendee
75
-
76
- protected
77
-
78
- def init
79
- # Parameter verarbeiten
80
- @marker = get_key('marker', '*')
81
- @max_var = get_key('max-var', '10000').to_i
82
- filter = get_array('check', WA_UNKNOWN)
83
-
84
- src = get_array('source')
85
- mod = get_key('mode', 'all')
86
-
87
- # Daten verarbeiten
88
- @var_strings = get_key('variations')
89
- forward(STR_CMD_ERR, 'Ocr-variator: Konfiguration <ocr-variator> ist leer') if @var_strings.size==0
90
-
91
- # Initialisierungen
92
- @check = Hash.new(false)
93
- filter.each { |s| @check[s.upcase] = true }
94
-
95
- # Wörterbuchzugriff
96
- @dic = Dictionary.new({'source'=>src, 'mode'=>mod}, @lingo)
97
- @gra = Grammar.new({'source'=>src, 'mode'=>mod}, @lingo)
98
-
99
- # Optimierungen
100
- if @max_var == 0
101
- forward( STR_CMD_WARN, 'Ocr-variator: max-var ist 0, setze es auf 10.000' )
102
- @max_var = 10000
103
- end
104
- end
29
+ class Attendee
105
30
 
106
- def control(cmd, par)
107
- # Status wird abgefragt
108
- if cmd == STR_CMD_STATUS
109
- # Eigenen Status um Status von Dictionary und Grammer erweitern
110
- @dic.report.each_pair { | k, v | set( k, v ) }
111
- @gra.report.each_pair { | k, v | set( k, v ) }
31
+ # Der Variator ermöglicht bei nicht erkannten Wörtern den listenbasierten
32
+ # Austausch einzelner Wortteile einchließlich erneuter Wörterbuchsuche zur
33
+ # Verbesserung der Worterkennungsquote.
34
+ #
35
+ # Ursprünglich wurde der Variator entwickelt, um die mangelnde Qualität bei der
36
+ # OCR-Erkennung altdeutscher 's'-Konsonanten zu optimieren. Er kann ebenso bei
37
+ # alternativen Umlautschreibweisen z.B. zur Wandlung von 'Koeln' in 'Köln' dienen.
38
+ #
39
+ # === Mögliche Verlinkung
40
+ # Erwartet:: Daten vom Typ *Word* (andere werden einfach durchgereicht) z.B. von Wordsearcher
41
+ # Erzeugt:: Daten vom Typ *Word* zur Weiterleitung z.B. an Synonymer, Decomposer, Multiworder, Sequencer, Noneword_filter oder Vector_filter
42
+ #
43
+ # === Parameter
44
+ # Kursiv dargestellte Parameter sind optional (ggf. mit Angabe der Voreinstellung).
45
+ # Alle anderen Parameter müssen zwingend angegeben werden.
46
+ # <b>in</b>:: siehe allgemeine Beschreibung des Attendee
47
+ # <b>out</b>:: siehe allgemeine Beschreibung des Attendee
48
+ # <b>source</b>:: siehe allgemeine Beschreibung des Dictionary
49
+ # <b><i>mode</i></b>:: (Standard: all) siehe allgemeine Beschreibung des Dictionary
50
+ # <b><i>^check</i></b>:: (Standard: WA_UNKNOWN) Gebrenzt die zu variierenden Worttypen
51
+ # <b><i>marker</i></b>:: (Standard: '*') Kennzeichnung durch Variation erkannter Wörter
52
+ # <b><i>max-var</i></b>:: (Standard: '10000') Begrenzung der maximal zu prüfenden Permutationen bei der vollständigen Kombination aller auf ein Wort anzuwendenen aufgelisteten Wortteile.
53
+ #
54
+ # === Beispiele
55
+ # Bei der Verarbeitung einer normalen Textdatei mit der Ablaufkonfiguration <tt>t1.cfg</tt>
56
+ # meeting:
57
+ # attendees:
58
+ # - text_reader: { out: lines, files: '$(files)' }
59
+ # - tokenizer: { in: lines, out: token }
60
+ # - word_searcher: { in: abbrev, out: words, source: 'sys-dic' }
61
+ # - variator: { in: words, out: varios, source: 'sys-dic' }
62
+ # - debugger: { in: varios, prompt: 'out>' }
63
+ # ergibt die Ausgabe über den Debugger: <tt>lingo -c t1 test.txt</tt>
64
+ # out> *FILE('test.txt')
65
+ # out> <*Dies = [(dies/w)]>
66
+ # out> <*ist = [(ist/t)]>
67
+ # out> <ein = [(ein/t)]>
68
+ # out> <*Tisch = [(tisch/s)]>
69
+ # out> :./PUNC:
70
+ # out> *EOL('test.txt')
71
+ # out> *EOF('test.txt')
72
+
73
+ class Variator < self
74
+
75
+ protected
76
+
77
+ def init
78
+ # Parameter verarbeiten
79
+ @marker = get_key('marker', '*')
80
+ @max_var = get_key('max-var', '10000').to_i
81
+ filter = get_array('check', WA_UNKNOWN)
82
+
83
+ # Daten verarbeiten
84
+ @var_strings = get_key('variations')
85
+ raise MissingConfigError.new(:variations) if @var_strings.empty?
86
+
87
+ # Initialisierungen
88
+ @check = Hash.new(false)
89
+ filter.each { |s| @check[s.upcase] = true }
90
+
91
+ set_dic
92
+ set_gra
93
+
94
+ if @max_var.zero?
95
+ @max_var = 10000
96
+ @lingo.warn "#{self.class}: max-var is 0, setting to #{@max_var}"
97
+ end
112
98
  end
113
- end
114
99
 
115
- def process(obj)
116
- # Zu prüfende Wörter filtern
117
- if obj.is_a?(Word) && @check[obj.attr]
118
- # Statistik für Report
119
- inc('Anzahl gesuchter Wörter')
120
-
121
- # Erzeuge Variationen einer Wortform
122
- variations = [obj.form]
123
- @var_strings.each do |switch|
124
- from, to = switch
125
- variations = variate(variations, from, to)
100
+ def control(cmd, par)
101
+ # Status wird abgefragt
102
+ if cmd == STR_CMD_STATUS
103
+ # Eigenen Status um Status von Dictionary und Grammer erweitern
104
+ @dic.report.each_pair { | k, v | set( k, v ) }
105
+ @gra.report.each_pair { | k, v | set( k, v ) }
126
106
  end
107
+ end
127
108
 
128
- # Prüfe Variation auf bekanntes Wort
129
- variations[0...@max_var].each do |var|
130
- # Variiertes Wort im Wörterbuch suchen
131
- word = @dic.find_word(var)
132
- word = @gra.find_compositum(var) if word.attr == WA_UNKNOWN
133
- next if word.attr == WA_UNKNOWN || (
134
- word.attr == WA_KOMPOSITUM && word.lexicals.any? { |lex|
135
- lex.attr[0..0] == LA_TAKEITASIS
136
- }
137
- )
138
-
139
- # Das erste erkannte Wort beendet die Suche
140
- inc('Anzahl gefundener Wörter')
141
- word.form = @marker + var
142
- forward(word)
143
- return
109
+ def process(obj)
110
+ # Zu prüfende Wörter filtern
111
+ if obj.is_a?(Word) && @check[obj.attr]
112
+ # Statistik für Report
113
+ inc('Anzahl gesuchter Wörter')
114
+
115
+ # Erzeuge Variationen einer Wortform
116
+ variations = [obj.form]
117
+ @var_strings.each do |switch|
118
+ from, to = switch
119
+ variations = variate(variations, from, to)
120
+ end
121
+
122
+ # Prüfe Variation auf bekanntes Wort
123
+ variations[0...@max_var].each do |var|
124
+ # Variiertes Wort im Wörterbuch suchen
125
+ word = @dic.find_word(var)
126
+ word = @gra.find_compositum(var) if word.unknown?
127
+ next if word.unknown? || (
128
+ word.attr == WA_KOMPOSITUM && word.lexicals.any? { |lex|
129
+ lex.attr[0..0] == LA_TAKEITASIS
130
+ }
131
+ )
132
+
133
+ # Das erste erkannte Wort beendet die Suche
134
+ inc('Anzahl gefundener Wörter')
135
+ word.form = @marker + var
136
+ forward(word)
137
+ return
138
+ end
144
139
  end
145
- end
146
140
 
147
- forward(obj)
148
- end
141
+ forward(obj)
142
+ end
149
143
 
150
- private
144
+ private
151
145
 
152
- # Variiere die Bestandteile eines Arrays gemäß den Austauschvorgaben.
153
- #
154
- # variate( 'Tiieh', 'ieh', 'sch' ) => ['Tiieh', 'Tisch']
155
- def variate(variation_list, from, to)
156
- # neue Varianten sammeln
157
- add_variations = []
158
- from_re = Regexp.new(from)
146
+ # Variiere die Bestandteile eines Arrays gemäß den Austauschvorgaben.
147
+ #
148
+ # variate( 'Tiieh', 'ieh', 'sch' ) => ['Tiieh', 'Tisch']
149
+ def variate(variation_list, from, to)
150
+ # neue Varianten sammeln
151
+ add_variations = []
152
+ from_re = Regexp.new(from)
159
153
 
160
- # alle Wörter in der variation_list permutieren
161
- variation_list.each do |wordform|
154
+ # alle Wörter in der variation_list permutieren
155
+ variation_list.each do |wordform|
162
156
 
163
- # Wortform in Teile zerlegen und anschließend Dimension feststellen
164
- wordpart = " #{wordform} ".split( from_re )
165
- n = wordpart.size - 1
157
+ # Wortform in Teile zerlegen und anschließend Dimension feststellen
158
+ wordpart = " #{wordform} ".split( from_re )
159
+ n = wordpart.size - 1
166
160
 
167
- # Austauschketten in Matrix hinterlegen
168
- change = [from, to]
161
+ # Austauschketten in Matrix hinterlegen
162
+ change = [from, to]
169
163
 
170
- # Austauschketten auf alle Teile anwenden
171
- (1..(2**n-1)).each do |i|
172
- variation = wordpart[0]
173
- # i[x] = Wert des x.ten Bit von Integer i
174
- (1..n).each { |j| variation += change[i[j-1]] + wordpart[j] }
164
+ # Austauschketten auf alle Teile anwenden
165
+ (1..(2**n-1)).each do |i|
166
+ variation = wordpart[0]
167
+ # i[x] = Wert des x.ten Bit von Integer i
168
+ (1..n).each { |j| variation += change[i[j-1]] + wordpart[j] }
175
169
 
176
- add_variations << variation.strip
170
+ add_variations << variation.strip
171
+ end
177
172
  end
173
+
174
+ variation_list + add_variations
178
175
  end
179
176
 
180
- variation_list + add_variations
181
177
  end
182
178
 
183
179
  end