lingo 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (108) hide show
  1. data/.rspec +1 -0
  2. data/COPYING +663 -0
  3. data/ChangeLog +754 -0
  4. data/README +322 -0
  5. data/Rakefile +100 -0
  6. data/TODO +28 -0
  7. data/bin/lingo +5 -0
  8. data/bin/lingoctl +6 -0
  9. data/de.lang +121 -0
  10. data/de/lingo-abk.txt +74 -0
  11. data/de/lingo-dic.txt +56822 -0
  12. data/de/lingo-mul.txt +3209 -0
  13. data/de/lingo-syn.txt +14841 -0
  14. data/de/test_dic.txt +24 -0
  15. data/de/test_mul.txt +17 -0
  16. data/de/test_mul2.txt +2 -0
  17. data/de/test_singleword.txt +2 -0
  18. data/de/test_syn.txt +4 -0
  19. data/de/test_syn2.txt +1 -0
  20. data/de/user-dic.txt +10 -0
  21. data/en.lang +113 -0
  22. data/en/lingo-dic.txt +55434 -0
  23. data/en/lingo-mul.txt +456 -0
  24. data/en/user-dic.txt +5 -0
  25. data/info/Objekte.png +0 -0
  26. data/info/Typen.png +0 -0
  27. data/info/database.png +0 -0
  28. data/info/db_small.png +0 -0
  29. data/info/download.png +0 -0
  30. data/info/gpl-hdr.txt +27 -0
  31. data/info/kerze.png +0 -0
  32. data/info/language.png +0 -0
  33. data/info/lingo.png +0 -0
  34. data/info/logo.png +0 -0
  35. data/info/meeting.png +0 -0
  36. data/info/types.png +0 -0
  37. data/lib/lingo.rb +321 -0
  38. data/lib/lingo/attendee/abbreviator.rb +119 -0
  39. data/lib/lingo/attendee/debugger.rb +111 -0
  40. data/lib/lingo/attendee/decomposer.rb +101 -0
  41. data/lib/lingo/attendee/dehyphenizer.rb +167 -0
  42. data/lib/lingo/attendee/multiworder.rb +301 -0
  43. data/lib/lingo/attendee/noneword_filter.rb +103 -0
  44. data/lib/lingo/attendee/objectfilter.rb +86 -0
  45. data/lib/lingo/attendee/sequencer.rb +190 -0
  46. data/lib/lingo/attendee/synonymer.rb +105 -0
  47. data/lib/lingo/attendee/textreader.rb +237 -0
  48. data/lib/lingo/attendee/textwriter.rb +196 -0
  49. data/lib/lingo/attendee/tokenizer.rb +218 -0
  50. data/lib/lingo/attendee/variator.rb +185 -0
  51. data/lib/lingo/attendee/vector_filter.rb +158 -0
  52. data/lib/lingo/attendee/wordsearcher.rb +96 -0
  53. data/lib/lingo/attendees.rb +289 -0
  54. data/lib/lingo/cli.rb +62 -0
  55. data/lib/lingo/config.rb +104 -0
  56. data/lib/lingo/const.rb +131 -0
  57. data/lib/lingo/ctl.rb +173 -0
  58. data/lib/lingo/database.rb +587 -0
  59. data/lib/lingo/language.rb +530 -0
  60. data/lib/lingo/modules.rb +98 -0
  61. data/lib/lingo/types.rb +285 -0
  62. data/lib/lingo/utilities.rb +40 -0
  63. data/lib/lingo/version.rb +27 -0
  64. data/lingo-all.cfg +85 -0
  65. data/lingo-call.cfg +15 -0
  66. data/lingo.cfg +78 -0
  67. data/lingo.rb +3 -0
  68. data/lir.cfg +72 -0
  69. data/porter/stem.cfg +311 -0
  70. data/porter/stem.rb +150 -0
  71. data/spec/spec_helper.rb +0 -0
  72. data/test.cfg +79 -0
  73. data/test/attendee/ts_abbreviator.rb +35 -0
  74. data/test/attendee/ts_decomposer.rb +31 -0
  75. data/test/attendee/ts_multiworder.rb +390 -0
  76. data/test/attendee/ts_noneword_filter.rb +19 -0
  77. data/test/attendee/ts_objectfilter.rb +19 -0
  78. data/test/attendee/ts_sequencer.rb +43 -0
  79. data/test/attendee/ts_synonymer.rb +33 -0
  80. data/test/attendee/ts_textreader.rb +58 -0
  81. data/test/attendee/ts_textwriter.rb +98 -0
  82. data/test/attendee/ts_tokenizer.rb +32 -0
  83. data/test/attendee/ts_variator.rb +24 -0
  84. data/test/attendee/ts_vector_filter.rb +62 -0
  85. data/test/attendee/ts_wordsearcher.rb +119 -0
  86. data/test/lir.csv +3 -0
  87. data/test/lir.txt +12 -0
  88. data/test/lir2.txt +12 -0
  89. data/test/mul.txt +1 -0
  90. data/test/ref/artikel.mul +1 -0
  91. data/test/ref/artikel.non +159 -0
  92. data/test/ref/artikel.seq +270 -0
  93. data/test/ref/artikel.syn +16 -0
  94. data/test/ref/artikel.vec +928 -0
  95. data/test/ref/artikel.ven +928 -0
  96. data/test/ref/artikel.ver +928 -0
  97. data/test/ref/lir.csv +328 -0
  98. data/test/ref/lir.mul +1 -0
  99. data/test/ref/lir.non +274 -0
  100. data/test/ref/lir.seq +249 -0
  101. data/test/ref/lir.syn +94 -0
  102. data/test/test_helper.rb +113 -0
  103. data/test/ts_database.rb +269 -0
  104. data/test/ts_language.rb +396 -0
  105. data/txt/artikel-en.txt +157 -0
  106. data/txt/artikel.txt +170 -0
  107. data/txt/lir.txt +1317 -0
  108. metadata +211 -0
@@ -0,0 +1,237 @@
1
+ # encoding: utf-8
2
+
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
28
+ #++
29
+
30
+ %w[filemagic mime/types hpricot pdf-reader].each { |lib|
31
+ begin
32
+ require lib
33
+ rescue LoadError
34
+ end
35
+ }
36
+
37
+ class Lingo
38
+
39
+ # Der Textreader ist eine klassische Datenquelle. Er liest eine oder mehrere Dateien
40
+ # und gibt sie Zeilenweise in den Ausgabekanal. Der Start bzw. Wechsel einer Datei
41
+ # wird dabei über den Kommandokanal angekündigt, ebenso wie das Ende.
42
+ #
43
+ # Der Textreader kann ebenfalls ein spezielles Dateiformat verarbeiten, welches zum
44
+ # Austausch mit dem LIR-System dient. Dabei enthält die Datei Record-basierte Informationen,
45
+ # die wie mehrere Dateien verarbeitet werden.
46
+ #
47
+ # === Mögliche Verlinkung
48
+ # Erzeugt:: Daten des Typs *String* (Textzeile) z.B. für Tokenizer, 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>out</b>:: siehe allgemeine Beschreibung des Attendee
54
+ # <b>files</b>:: Es können eine oder mehrere Dateien angegeben werden, die nacheinander
55
+ # eingelesen und zeilenweise weitergeleitet werden. Die Dateien werden mit
56
+ # Komma voneinander getrennt, z.B.
57
+ # files: 'readme.txt'
58
+ # files: 'readme.txt,lingo.cfg'
59
+ # <b><i>lir-record-pattern</i></b>:: Mit diesem Parameter wird angegeben, woran der Anfang
60
+ # eines neuen Records erkannt werden kann und wie die
61
+ # Record-Nummer identifiziert wird. Das Format einer
62
+ # LIR-Datei ist z.B.
63
+ # [00001.]
64
+ # 020: ¬Die Aufgabenteilung zwischen Wortschatz und Grammatik.
65
+ #
66
+ # [00002.]
67
+ # 020: Nicht-konventionelle Thesaurusrelationen als Orientierungshilfen.
68
+ # Mit der Angabe von
69
+ # lir-record-pattern: "^\[(\d+)\.\]"
70
+ # werden die Record-Zeilen erkannt und jeweils die Record-Nummer +00001+,
71
+ # bzw. +00002+ erkannt.
72
+ #
73
+ # === Generierte Kommandos
74
+ # Damit der nachfolgende Datenstrom einwandfrei verarbeitet werden kann, generiert der Textreader
75
+ # Kommandos, die mit in den Datenstrom eingefügt werden.
76
+ # <b>*FILE(<dateiname>)</b>:: Kennzeichnet den Beginn der Datei <dateiname>
77
+ # <b>*EOF(<dateiname>)</b>:: Kennzeichnet das Ende der Datei <dateiname>
78
+ # <b>*LIR_FORMAT('')</b>:: Kennzeichnet die Verarbeitung einer Datei im LIR-Format (nur bei LIR-Format).
79
+ # <b>*RECORD(<nummer>)</b>:: Kennzeichnet den Beginn eines neuen Records (nur bei LIR-Format).
80
+ # === Beispiele
81
+ # Bei der Verarbeitung einer normalen Textdatei mit der Ablaufkonfiguration <tt>t1.cfg</tt>
82
+ # meeting:
83
+ # attendees:
84
+ # - textreader: { out: lines, files: '$(files)' }
85
+ # - debugger: { in: lines, prompt: 'out>' }
86
+ # ergibt die Ausgabe über den Debugger: <tt>lingo -c t1 test.txt</tt>
87
+ # out> *FILE('test.txt')
88
+ # out> "Dies ist eine Zeile."
89
+ # out> "Dies ist noch eine."
90
+ # out> *EOF('test.txt')
91
+ # Bei der Verarbeitung einer LIR-Datei mit der Ablaufkonfiguration <tt>t2.cfg</tt>
92
+ # meeting:
93
+ # attendees:
94
+ # - textreader: { out: lines, files: '$(files)', lir-record-pattern: "^\[(\d+)\.\]" }
95
+ # - debugger: { in: lines, prompt: 'out>'}
96
+ # ergibt die Ausgabe mit <tt>lingo -c t2 lir.txt</tt>
97
+ # out> *LIR-FORMAT('')
98
+ # out> *FILE('lir.txt')
99
+ # out> *RECORD('00001')
100
+ # out> "020: \254Die Aufgabenteilung zwischen Wortschatz und Grammatik."
101
+ # out> *RECORD('00002')
102
+ # out> "020: Nicht-konventionelle Thesaurusrelationen als Orientierungshilfen."
103
+ # out> *EOF('lir.txt')
104
+
105
+ class Attendee::Textreader < Attendee
106
+
107
+ protected
108
+
109
+ # TODO: FILE und LIR-FILE
110
+ # TODO: lir-record-pattern abkürzen
111
+ # Interpretation der Parameter
112
+ def init
113
+ @files = Array(get_key('files', '-'))
114
+ @rec_pat = Regexp.new(get_key('lir-record-pattern', ''))
115
+ @is_LIR_file = has_key?('lir-record-pattern')
116
+ @chomp = get_key('chomp', true)
117
+ @filter = get_key('filter', false)
118
+ end
119
+
120
+ def control(cmd, param)
121
+ if cmd==STR_CMD_TALK
122
+ forward(STR_CMD_LIR, '') if @is_LIR_file
123
+ @files.each { |filename| spool(filename) }
124
+ end
125
+ end
126
+
127
+ private
128
+
129
+ # Gibt eine Datei zeilenweise in den Ausgabekanal
130
+ def spool(filename)
131
+ unless stdin?(filename)
132
+ FileTest.exist?(filename) || forward(STR_CMD_ERR, "Datei #{filename} nicht gefunden")
133
+
134
+ inc('Anzahl Dateien')
135
+ add('Anzahl Bytes', File.stat(filename).size)
136
+ end
137
+
138
+ forward(STR_CMD_FILE, filename)
139
+
140
+ filter(filename) { |line|
141
+ inc('Anzahl Zeilen')
142
+ line.chomp! if @chomp
143
+ line.gsub!(/\303\237/, "ß")
144
+ ### HACK
145
+ if @is_LIR_file && line =~ @rec_pat
146
+ forward(STR_CMD_RECORD, $1)
147
+ else
148
+ forward(line) if line.size>0
149
+ end
150
+ }
151
+
152
+ forward(STR_CMD_EOF, filename)
153
+ end
154
+
155
+ def filter(filename, &block)
156
+ file = stdin?(filename) ?
157
+ @lingo.config.stdin.set_encoding(ENC) :
158
+ File.open(filename, 'rb', encoding: ENC)
159
+
160
+ file = case @filter == true ? file_type(filename, file) : @filter.to_s
161
+ when /html/ then filter_html(file)
162
+ when /xml/ then filter_html(file, true)
163
+ when /pdf/ then filter_pdf(file, &block) or return
164
+ else file
165
+ end if @filter
166
+
167
+ file.each_line(&block)
168
+ end
169
+
170
+ def filter_pdf(file, &block)
171
+ if Object.const_defined?(:PDF) && PDF.const_defined?(:Reader)
172
+ PDFFilter.filter(file, &block)
173
+ nil
174
+ else
175
+ warn "PDF filter not available. Please install `pdf-reader'."
176
+ file
177
+ end
178
+ end
179
+
180
+ def filter_html(file, xml = false)
181
+ if Object.const_defined?(:Hpricot)
182
+ Hpricot(file, xml: xml).inner_text
183
+ else
184
+ warn "#{xml ? 'X' : 'HT'}ML filter not available. Please install `hpricot'."
185
+ file
186
+ end
187
+ end
188
+
189
+ def file_type(filename, file)
190
+ if Object.const_defined?(:FileMagic) && file.respond_to?(:rewind)
191
+ type = FileMagic.fm(:mime, simplified: true).buffer(file.read(256))
192
+ file.rewind
193
+ type
194
+ elsif Object.const_defined?(:MIME) && MIME.const_defined?(:Types)
195
+ if type = MIME::Types.of(filename).first
196
+ type.content_type
197
+ else
198
+ warn 'Filters not available. File type could not be determined.'
199
+ nil
200
+ end
201
+ else
202
+ warn "Filters not available. Please install `ruby-filemagic' or `mime-types'."
203
+ nil
204
+ end
205
+ end
206
+
207
+ def stdin?(filename)
208
+ %w[STDIN -].include?(filename)
209
+ end
210
+
211
+ class PDFFilter
212
+
213
+ def self.filter(file, &block)
214
+ PDF::Reader.new.parse(file, new(&block))
215
+ end
216
+
217
+ def initialize(&block)
218
+ @block = block
219
+ end
220
+
221
+ def show_text(string, *params)
222
+ @block[string << '|']
223
+ end
224
+
225
+ alias_method :super_show_text, :show_text
226
+ alias_method :move_to_next_line_and_show_text, :show_text
227
+ alias_method :set_spacing_next_line_show_text, :show_text
228
+
229
+ def show_text_with_positioning(params, *)
230
+ params.each { |param| show_text(param) if param.is_a?(String) }
231
+ end
232
+
233
+ end
234
+
235
+ end
236
+
237
+ end
@@ -0,0 +1,196 @@
1
+ # encoding: utf-8
2
+
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
28
+ #++
29
+
30
+ class Lingo
31
+
32
+ # Der Textwriter ermöglicht die Umleitung des Datenstroms in eine Textdatei. Dabei werden
33
+ # Objekte, die nicht vom Typ String sind in eine sinnvolle Textrepresentation gewandelt.
34
+ # Der Name der Ausgabedatei wird durch den Namen der Eingabedatei (des Textreaders) bestimmt.
35
+ # Es kann lediglich die Extension verändert werden. Der Textwriter kann auch das LIR-Format
36
+ # erzeugen.
37
+ #
38
+ # === Mögliche Verlinkung
39
+ # Erwartet:: Daten verschiedenen Typs
40
+ #
41
+ # === Parameter
42
+ # Kursiv dargestellte Parameter sind optional (ggf. mit Angabe der Voreinstellung).
43
+ # Alle anderen Parameter müssen zwingend angegeben werden.
44
+ # <b>in</b>:: siehe allgemeine Beschreibung des Attendee
45
+ # <b>out</b>:: siehe allgemeine Beschreibung des Attendee
46
+ # <b><i>ext</i></b>:: (Standard: txt2) Gibt die Dateinamen-Erweiertung für die Ausgabedatei an.
47
+ # Wird z.B. dem Textreader die Datei <tt>Dokument.txt</tt> angegeben und
48
+ # über die Lingo-Konfiguration alle Indexwörter herausgefiltert, kann mit
49
+ # <tt>ext: 'idx'</tt> der Textwriter veranlasst werden, die Indexwörter in
50
+ # die Datei <tt>Dokument.idx</tt> zu schreiben.
51
+ # <b><i>sep</i></b>:: (Standard: ' ') Gibt an, mit welchem Trennzeichen zwei aufeinanderfolgende
52
+ # Objekte in der Ausgabedatei getrennt werden sollen. Gängige Werte sind auch
53
+ # noch '\n', welches die Ausgabe jedes Objektes in eine Zeile ermöglicht.
54
+ # <b><i>lir-format</i></b>:: (Standard: false) Dieser Parameter hat keinen Wert. Wird er angegeben,
55
+ # dann wird er als true ausgewertet. Damit ist es möglich, die Ausgabedatei
56
+ # im für LIR lesbarem Format zu erstellen.
57
+ #
58
+ # === Beispiele
59
+ # Bei der Verarbeitung der oben angegebenen Funktionsbeschreibung des Textwriters mit der Ablaufkonfiguration <tt>t1.cfg</tt>
60
+ # meeting:
61
+ # attendees:
62
+ # - textreader: { out: lines, files: '$(files)' }
63
+ # - tokenizer: { in: lines, out: token }
64
+ # - wordsearcher: { in: token, out: words, source: 'sys-dic' }
65
+ # - vector_filter: { in: words, out: filtr, sort: 'term_rel' }
66
+ # - textwriter: { in: filtr, ext: 'vec', sep: '\n' }
67
+ # ergibt die Ausgabe in der Datei <tt>test.vec</tt>
68
+ # 0.03846 name
69
+ # 0.01923 ausgabedatei
70
+ # 0.01923 datenstrom
71
+ # 0.01923 extension
72
+ # 0.01923 format
73
+ # 0.01923 objekt
74
+ # 0.01923 string
75
+ # 0.01923 textdatei
76
+ # 0.01923 typ
77
+ # 0.01923 umleitung
78
+
79
+ class Attendee::Textwriter < Attendee
80
+
81
+ protected
82
+
83
+ def init
84
+ @ext = get_key('ext', 'txt2')
85
+ @lir = get_key('lir-format', false)
86
+ @sep = @lir ? ' ' : eval("\"#{@config['sep'] || ' '}\"")
87
+ @no_sep, @no_puts = true, false
88
+ end
89
+
90
+ def control(cmd, par)
91
+ case cmd
92
+ when STR_CMD_LIR
93
+ @lir = true
94
+ when STR_CMD_FILE
95
+ @no_sep = true
96
+
97
+ if stdout?(@ext)
98
+ @filename = @ext
99
+ @file = @lingo.config.stdout
100
+ else
101
+ @filename = par.sub(/(\.[^.]+)?$/, '.'+@ext)
102
+ @file = File.new(@filename,'w')
103
+ inc('Anzahl Dateien')
104
+ end
105
+
106
+ @lir_rec_no = ''
107
+ @lir_rec_buf = Array.new
108
+ when STR_CMD_RECORD
109
+ @no_sep = true
110
+ if @lir
111
+ flush_lir_buffer
112
+ @lir_rec_no = par
113
+ end
114
+ when STR_CMD_EOL
115
+ @no_sep = true
116
+ unless @lir
117
+ @file.puts unless @no_puts # unless @sep=="\n"
118
+ inc('Anzahl Zeilen')
119
+ end
120
+ when STR_CMD_EOF
121
+ flush_lir_buffer if @lir
122
+
123
+ unless stdout?(@filename)
124
+ @file.close
125
+ add('Anzahl Bytes', File.stat(@filename).size)
126
+ end
127
+ end
128
+ end
129
+
130
+ def process(obj)
131
+ if @lir
132
+ @lir_rec_buf << (obj.kind_of?(Token) ? obj.form : obj.to_s)
133
+ else
134
+ @file.print @sep unless @no_sep
135
+ @no_sep=false if @no_sep
136
+ if obj.is_a?(Word) || obj.is_a?(Token)
137
+ @file.print obj.form
138
+ else
139
+ @file.print obj
140
+ end
141
+ end
142
+ end
143
+
144
+ private
145
+
146
+ def flush_lir_buffer
147
+ unless @lir_rec_no.empty? || @lir_rec_buf.empty?
148
+ if @sep =~ /\n/
149
+ @file.print '*', @lir_rec_no, "\n", @lir_rec_buf.join(@sep), "\n"
150
+ else
151
+ @file.print @lir_rec_no, '*', @lir_rec_buf.join(@sep), "\n"
152
+ end
153
+ end
154
+ @lir_rec_no = ''
155
+ @lir_rec_buf.clear
156
+ end
157
+
158
+ def stdout?(filename)
159
+ %w[STDOUT -].include?(filename)
160
+ end
161
+
162
+ end
163
+
164
+ class Attendee::Formatter < Attendee::Textwriter
165
+
166
+ protected
167
+
168
+ def init
169
+ super
170
+
171
+ @ext = get_key('ext', '-')
172
+ @format = get_key('format', '%s')
173
+ @map = get_key('map', Hash.new { |h, k| h[k] = k })
174
+
175
+ @no_puts = true
176
+ end
177
+
178
+ def process(obj)
179
+ if obj.is_a?(Word) || obj.is_a?(Token)
180
+ str = obj.form
181
+
182
+ if obj.respond_to?(:lexicals)
183
+ lex = obj.lexicals.first # TODO
184
+ att = @map[lex.attr] if lex
185
+ str = @format % [str, lex.form, att] if att
186
+ end
187
+ else
188
+ str = obj.to_s
189
+ end
190
+
191
+ @lir ? @lir_rec_buf << str : @file.print(str)
192
+ end
193
+
194
+ end
195
+
196
+ end
@@ -0,0 +1,218 @@
1
+ # encoding: utf-8
2
+
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
28
+ #++
29
+
30
+ class Lingo
31
+
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
128
+ end
129
+ }
130
+
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
144
+
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
150
+ end
151
+ end
152
+
153
+ def process(obj)
154
+ if obj.is_a?(String)
155
+ inc('Anzahl Zeilen')
156
+
157
+ tokenize(obj) { |form, attr|
158
+ token = Token.new(form, attr)
159
+
160
+ inc('Anzahl Muster '+token.attr)
161
+ inc('Anzahl Token')
162
+
163
+ forward(token)
164
+ }
165
+
166
+ forward(STR_CMD_EOL, @filename) if @filename
167
+ else
168
+ forward(obj)
169
+ end
170
+ end
171
+
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
198
+
199
+ if !@wiki && textline =~ /\[\[[^\[\]]*$/
200
+ yield $~[0], @cont = 'WIKI'
201
+ textline = $`
202
+ end
203
+ end
204
+
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
+ end
215
+
216
+ end
217
+
218
+ end