lingo 1.8.0

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 (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