oddb2xml 2.0.9 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,15 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 927b0bc8d96d6ed56d7bb1daf1c9620483ff10ce
4
- data.tar.gz: 9544ef85b62183a230dba6b97cb8b4c7f64936fa
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ MWIzODZlNjVlYTgzMzIxNDUwNmQ1NjgwMjdhNGFkNWEwNmI2NjExYQ==
5
+ data.tar.gz: !binary |-
6
+ NDYwYWMxMmQ5YjVlNWM4NmNlOTU4NWY0NDU2YjRhZThlNTUzNjhmNw==
5
7
  SHA512:
6
- metadata.gz: 13910208d9a0c0ef08dc1f9d8c8272ea2d5098b6d010c94473c6ff4063b9a8f5b7e09bad77332a2ef476725b8426ab363b6676dd0bc9cea0023ade6e5d7d77e8
7
- data.tar.gz: 388bea5552438eac7d3b4027d98785b27302cab874a5ee2e596655abfb2bed974f99ac8b7f423b71b9fae0986ffdcb204cae1bde4cce54d92f2ab9d8a5665580
8
+ metadata.gz: !binary |-
9
+ NzQ1OWJlMmVlZDMzM2ZkMDM0M2Q0MzNlNGEyNzYxNGE0YjYxN2FjM2RkNjM0
10
+ Y2Y0Yjk4YTkxZGY5YTBjODMzYWE2ZjQ3NGZlMzU5YTUxZmI0N2QxZGY5MDQ0
11
+ YjRjMWIyNWNmZGI1YzYyOTBiODU2MjU1MDFkODU5MjIyOTczYjE=
12
+ data.tar.gz: !binary |-
13
+ MjIxZWJkY2JmNzhlOGNhNTljMDUwZmU3YThhODAwYTNiNTYxMTg0MDE3ZDcy
14
+ MGMzNjA0MGY4ODFlZWJjM2MzYzIxOTU4MTVkOWVhMTUxMzBhOTE4MDQ5OTM3
15
+ ODY4ZDY0ZWNjZDQ1YzY2NTQ0ZDQyNDI1MjgxYmYwNDkyNzcyMTY=
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- oddb2xml (2.0.8)
4
+ oddb2xml (2.1.0)
5
5
  archive-tar-minitar (~> 0.5.2)
6
6
  mechanize (~> 2.5.1)
7
7
  nokogiri (~> 1.5.10)
data/History.txt CHANGED
@@ -1,3 +1,7 @@
1
+ === 2.1.0 / 12.05.2015
2
+
3
+ * --calc uses now a parser to split Column-C into the preparationname and the galenic-form
4
+
1
5
  === 2.0.9 / 05.05.2015
2
6
 
3
7
  * rm /downloads when running with option "-e"
@@ -23,34 +23,152 @@ Die Syntax wird in einer Datei "compositions_syntax":https://raw.githubuserconte
23
23
 
24
24
  h2. Gebrauchte Abkürzungen und Schlüsselworte
25
25
 
26
- - et alia := es gibt noch andere Substanzen. Beispiel: 62504 Olanzapin Sandoz Solufilm 20 mg
27
- - et oder , := trennen Substanzen. Beispiel: 29555 NaCl 11,7 % B. Braun, Zusatzampullen zu Infusionslösungen
28
- - ut := vorgehende Substanz wird via nachstehend aufgeführte Salze(e) aufgenommen. Beispiel: 54749 Supradyn Vital 50+.
29
- - DER: := DrugEthanol Ratio
30
- - q.s. := quantum satis (genügend, meist ohne Limitenangabe)
31
- - pro praeparatione := pro Präparat
32
- - excipiens := Füllmittel
33
- - pro compresso obducto := pro Dragée
34
- - pro compresso := pro Tablette
35
- - pro praeparatione := pro Präparat
36
- - ad pulverem := zum Pulver hinzufügen
37
- - pro charta := pro Pulver Briefchen
26
+ - DER := DrugEthanol Ratio
27
+ - Diluens := Verdünnungsmittel
28
+ - Solutio reconstituta := angefertigte Lösung
29
+ - Solvens (i.m.) := Lösungsmittel (intramuskulär)
30
+ - Solvens (i.v.) := Lösungsmittel (intravenös)
31
+ - Solvens := Lösungsmittel
32
+ - ad emulsionem := zur Herstellung einer Emulsion
38
33
  - ad globulos := zu den Vaginalkugeln
39
- - aqua ad iniectabilia q.s. ad solutionem := genügend steriles Wasser zur Lösung/zum Lösen
40
- - solvens (i.v.): aqua ad iniectabilia := Lösungsmittel (intravenös): Wasser zu Injektionszwecken
34
+ - ad pulverem := zum Pulver hinzufügen
41
35
  - ad solutionem := füge zur Lösung hinzu
42
- - q.s. ad := quatum satis ad (genügend für/zu/zum)
43
- - aqua q.s. ad := genügend Wasser zu
44
- - saccharum ad := Zucker hinzufügen zu
36
+ - ad suspensionem := zur Herstellung einer Suspension
45
37
  - aether q.s. := genügend Äther/Aether/Ether
38
+ - ana partes := zu gleichen Teilen
39
+ - antiox. := Antioxidans (Oxidationshemmer)
46
40
  - aqua ad iniectabilia := Wasser zu Injektionszwecken
41
+ - aqua ad iniectabilia q.s. ad solutionem := genügend steriles Wasser zur Lösung/zum Lösen
42
+ - aqua ad iniectabilia q.s. ad solutionem pro := wie oben, jedoch für (pro) eine bestimmte Menge (oder best. Volumen)
43
+ - aqua ad solutionem pro := Wasser zur Herstellung einer Lösung von …...
44
+ - aqua q.s. := genügend Wasser ...
45
+ - aqua q.s. ad := entsprechende Menge Wasser für ...
46
+ - aqua q.s. ad emulsionem pro := genügende Menge Wasser zur Herstellung der … best. Menge …. an Emulsion
47
+ - aqua q.s. ad gelatum pro := genügend Wasser zur Herstellung eines Gel
48
+ - aqua q.s. ad solutionem pro := ausreichende Menge Wasser zur Herstellung einer (best. Menge/Volumen) einer Lösung
49
+ - aqua q.s. ad suspensionem pro := dito wie oben, jedoch für eine Suspension
50
+ - aquos := tdb, 52 Vorkommnisse, z.B. 53096 @Sanukehl Strep D6, homöopathische Tropfen@
51
+ - arom. := aromatisiert ?
52
+ - ca. := zirka
53
+ - color. := gefärbt
54
+ - conserv. := konserviert
55
+ - corresp. := entsprechend
56
+ - corresp. ca. := entsprechend etwa ...
57
+ - deklar. := angegeben
58
+ - doses := Dosen (Mehrzahl von Dosis)
59
+ - doses pro vase := tbd (26 Vorkommnisse, z.B. 48943, @Turbuhaler, Pulver mit Applikator@
60
+ - et alia := es gibt noch andere Substanzen. Beispiel 62504 Olanzapin Sandoz Solufilm 20 mg
61
+ - et oder , := trennen Substanzen. Beispiel 29555 NaCl 11,7 % B. Braun, Zusatzampullen zu Infusionslösungen
62
+ - excipiens := Füllmittel
63
+ - excipiens ad emulsionem pro := Füllmittel zur Herstellung einer Emulsion in einer bestimmten Menge/Volumen
64
+ - excipiens ad pulverem pro := wie oben, aber für ein Pulver
65
+ - excipiens ad solutionem pro := wie oben, einfach für ein best. Volumen einer Lösung
66
+ - excipiens pro compresso := Füllmittel für eine Tablette
67
+ - excipiens pro compresso obducto := Füllmittel für ein Dragée
68
+ - excipiens pro praeparatione := Füllmittel für das Präparat (welches?)
69
+ - mineralia := Mineralien (Minralsalze)
70
+ - pro capsula := je Kapsel
71
+ - pro charta := pro Pulver Briefchen
72
+ - pro compresso := pro Tablette
73
+ - pro compresso obducto := pro Dragée
74
+ - pro dosi := je Dosis
75
+ - pro praeparatione := pro Präparat
76
+ - pro vase := tbd, 84 Vorkommnisse, z.B. 52331 @Extra Dry Cow ad us.vet., Suspension in Injektoren@
77
+ - pro vitro := tbd, je Gläschen (Ampulle? oder was?). Z.B. 55763 @Menopur, Injektionspräparat@
78
+ - q.s. := quantum satis (genügend, meist ohne Limitenangabe)
79
+ - q.s. ad := quatum satis ad (genügend für/zu/zum)
80
+ - q.s. ad pulverem pro := genügend je Pulver zu ...
47
81
  - q.s. pro praeparatione := genügend für Präparat
48
- - ana partes := zu gleichen Teilen
82
+ - ratio := Verhältnis
83
+ - residui := tbd, übrig, aber wovon??, 24 Vorkommnisse, z.B. 58158 @Priorix-Tetra, Pulver und Lösungsmittel zur Herstellung einer Injektionslösung@
84
+ - saccharum ad := Zucker hinzufügen zu
85
+ - solvens (i.v.) aqua ad iniectabilia := Lösungsmittel (intravenös) Wasser zu Injektionszwecken
86
+ - q.s. ad pulverem pro genügend je Pulver zu …….
87
+ - ratio := Verhältnis
88
+ - residui := übrig, aber wovon??
89
+ - spag. := spagyrisches Medi, wahrscheinlich
90
+ - spec. := Spezies, Art
91
+ - spp. := Subspezies, Unterart
92
+ - ssp. := tbd, kommt einmal vor 55445 @Verintex, homöopathisch-spagyrische Lösung zur äusserlichen Anwendung@
93
+ - ut := vorgehende Substanz wird via nachstehend aufgeführte Salze(e) aufgenommen. Beispiel 54749 Supradyn Vital 50+.
94
+ - ut alia := tbd, kommt einmal vor 54749 @Supradyn Vital 50+, Filmtabletten@
95
+ - ut aqua ad iniectabilia q.s. ad emulsionem pro := in Form von genügend Wasser zur Herstellung einer best. Menge Emulsion
96
+ - var. := verschieden, Verschiedenes, ...
49
97
 
50
- h2. Vorgeschlag für Bereinigung
98
+ h2. Vorschlag für Bereinigung
51
99
 
52
100
  * SwissmedicErrorHandler
53
- * Corresp: als Label für Bestandteile
54
- * corresp. für zugehörende Substanz
101
+ * Corresp: als Label für Bestandteile immer Gross schreiben
102
+ * corresp. für zugehörende Substanz, immer klein schreiben
103
+ * Namen von Präparaten und Substanzen, welche Klammern, Anführungszeichen, etc enthalten, mit einfache Anführungszeichen umgeben, z.B. @2,2'-methylen-bis(6-tert.-butyl-4-methyl-phenolum)@ -> @"2,2'-methylen-bis(6-tert.-butyl-4-methyl-phenolum)"@. Dito für Namen, welche Zahlen enthalten wie @Macrogolum 3350@
55
104
  * @<@ durch @max.@ ersetzen (1 Mal)
56
105
  * @mind.@ durch @min.@ ersetzen, @min.@ kommt viel häufiger vor
106
+ * Alle Bereiche wie @2.4-60 GBq@ durch @2.4-60 GBq@ ersetzen, damit das maschinelle Parsen einfacher wird. Siehe auch Bemerkung über Dosis.
107
+
108
+ h2. Vorkommende Lebensmittelfarbstoffe (E 100-199), Konservierungsstoffe (E 200-299) und Antioxidantien und Säureregulatoren (E 300-399)
109
+
110
+ E 102 Tartrazin
111
+ E 104 Chinolingelb
112
+ E 106
113
+ E 110 Gelborange S
114
+ E 120 Echtes Karmin
115
+ E 122 Azorubin
116
+ E 123 Amaranth
117
+ E 124 Cochenillerot A
118
+ E 127 Erythrosin
119
+ E 129 Allurarot AC
120
+ E 131 Patentblau V
121
+ E 132 Indigotin I
122
+ E 133 Brillantblau FCF
123
+ E 141 Kupferhaltige Komplexe der Chlorophylle, kupferhaltige Komplexe der Chlorophylline
124
+ E 142 Grün S
125
+ E 150 Zuckerkulöre
126
+ E 151 Brillantschwarz BN
127
+ E 153 Pflanzenkohle
128
+ E 160
129
+ E 171 Titandioxid
130
+ E 172 Eisenoxide und -hydroxide
131
+ E 200 Sorbinsäure
132
+ E 202 Kaliumsorbat
133
+ E 210 Benzoesäure
134
+ E 211 Natriumbenzoat
135
+ E 214 4-Hydroxybenzoesäureethylester
136
+ E 215 Natrium-4-Hydroxybenzoesäureethylester
137
+ E 216 4-Hydroxybenzoesäurepropylester (nicht zugelassen)
138
+ E 217 Natrium-4-Hydroxybenzoesäurepropylester (nicht zugelassen)
139
+ E 218 4-Hydroxybenzoesäuremethylester
140
+ E 219 Natrium-4-Hydroxybenzoesäuremethylester
141
+ E 220 Schwefeldioxid / Schweflige Säure
142
+ E 221 Natriumsulfit
143
+ E 222 Natriumhydrogensulfit
144
+ E 223 Natriumdisulfit
145
+ E 224 Kaliumdisulfit
146
+ E 281 Natriumpropionat
147
+ E 300 Ascorbinsäure
148
+ E 301 Natriumascorbat
149
+ E 304 Ascorbylpalmitat, Ascorbylstearat
150
+ E 307 Alpha-Tocopherol
151
+ E 310 Propylgallat
152
+ E 311 Octylgallat
153
+ E 312 Dodecylgallat
154
+ E 320 Butylhydroxyanisol (BHA)
155
+ E 321 Butylhydroxytoluol (BHT)
156
+
157
+ h2. mit Vorsicht zu geniessende Konservierungsstoffe
158
+
159
+ kritisch im Hinblick auf Nebenwirkungen im menschlichen Körper, sind meines Wissens folgende Stoffe:
160
+
161
+ 214 PHB-Ester
162
+ 215 PHB-Ethylester-Natriumsalz
163
+ 218 PHB-Methylester
164
+ 219 PHB-Methylester-Natriumsalz
165
+ 220 Schwefeldioxid
166
+ 221 Natriumsulfit
167
+ 222 Natriumhydrogensulfit
168
+ 223 Natriummetabisulfit
169
+ 224 Kaliummetabisulfit
170
+ 226 Calciumsulfit
171
+
172
+ Aber Vorsicht: Patienten können auch auf andere Zusatzstoffe reagieren - meist Reaktionen allergischer Natur. Gemeinhin treten primär gastro-intestinale Probleme auf (angefangen bei schlechtem Mundgeruch bis hin zu akuter Diarrhöe (Durchfall), Übelkeit, Kopfschmerzen, Hautausschläge, Jucken usw.).
173
+
174
+ Für Kleininder kann Banzylalkohol (z.T. auch in Schokoladewaren) schlimme Folgen haben. Darum dürfen Ampullenlösungen für die Pädiatrie NIE Benzylakohol als Konservierungsmittel enthalten!
@@ -698,7 +698,7 @@ module Oddb2xml
698
698
  items[ean13] = info
699
699
  xml.ARTICLE {
700
700
  xml.GTIN ean13
701
- xml.NAME info.name
701
+ xml.NAME info.column_c
702
702
  xml.PKG_SIZE info.pkg_size
703
703
  xml.SELLING_UNITS info.selling_units
704
704
  xml.MEASURE info.measure # Nur wenn Lösung wen Spalte M ml, Spritze
data/lib/oddb2xml/calc.rb CHANGED
@@ -103,7 +103,7 @@ module Oddb2xml
103
103
  @@names_without_galenic_forms = []
104
104
  @@rules_counter = {}
105
105
  attr_accessor :galenic_form, :unit, :pkg_size
106
- attr_reader :name, :substances, :composition, :compositions
106
+ attr_reader :name, :substances, :composition, :compositions, :column_c
107
107
  attr_reader :selling_units, :count, :multi, :measure, :addition, :scale # s.a. commercial_form in oddb.org/src/model/part.rb
108
108
  def self.get_galenic_group(name, lang = 'de')
109
109
  @@galenic_groups.values.collect { |galenic_group|
@@ -156,16 +156,32 @@ private
156
156
  string ? string.to_s.gsub(/\s\s+/, ' ') : nil
157
157
  end
158
158
  public
159
- def initialize(name = nil, size = nil, unit = nil, active_substance = nil, composition= nil)
160
- @name = remove_duplicated_spaces(name)
159
+ def initialize(column_c = nil, size = nil, unit = nil, active_substance = nil, composition= nil)
160
+ @column_c = column_c ? column_c.gsub(/\s\s+/, ' ') : nil
161
+ @name, gal_form = ParseGalenicForm.from_string(column_c)
162
+ gal_form = gal_form.gsub(/\s\s+/, ' ').sub(' / ', '/') if gal_form
163
+ @galenic_form = search_galenic_info(gal_form)
161
164
  @pkg_size = remove_duplicated_spaces(size)
162
165
  @unit = unit
163
- # @pkg_size, @galenic_group, @galenic_form =
164
- search_galenic_info
166
+ @selling_units = get_selling_units(@name, @pkg_size, @unit)
165
167
  @composition = composition
166
168
  @measure = unit if unit and not @measure
169
+ unless @galenic_form
170
+ parts = column_c.split(/\s+|,|\-/)
171
+ parts.each{
172
+ |part|
173
+ if idx = search_exact_galform(part)
174
+ @galenic_form = idx
175
+ break
176
+ end
177
+ }
178
+ end if column_c
179
+ if @measure and not @galenic_form
180
+ @galenic_form ||= search_exact_galform(@measure)
181
+ @galenic_form ||= search_exact_galform(@measure.sub('(n)', 'n'))
182
+ end
183
+ handle_unknown_galform(gal_form)
167
184
  @measure = @galenic_form.description if @galenic_form and not @measure
168
- @galenic_form ||= @@galenic_forms[UnknownGalenicForm]
169
185
 
170
186
  unless composition
171
187
  @compositions = []
@@ -193,9 +209,6 @@ public
193
209
  galenic_group ? galenic_group.description : ''
194
210
  ]
195
211
  end
196
- def galenic_form__xxx
197
- @galenic_form.description
198
- end
199
212
  private
200
213
 
201
214
  def update_rule(rulename)
@@ -291,63 +304,49 @@ public
291
304
  return 1
292
305
  end
293
306
  end
294
- # Parse a string for a numerical value and unit, e.g. 1.5 ml
295
- def self.check_for_value_and_units(what)
296
- if m = /^([\d.]+)\s*(\D+)/.match(what)
297
- # return [m[1], m[2] ]
298
- return m[0].to_s
299
- else
300
- nil
307
+
308
+ def search_exact_galform(name)
309
+ return nil unless name
310
+ if idx = @@galenic_forms.values.find{|x| x.descriptions['de'] and x.descriptions['de'].downcase.eql?(name.downcase) } or
311
+ idx = @@galenic_forms.values.find{|x| x.descriptions['fr'] and x.descriptions['fr'].downcase.eql?(name.downcase) } or
312
+ idx = @@galenic_forms.values.find{|x| x.descriptions['en'] and x.descriptions['en'].downcase.eql?(name.downcase) }
313
+ return idx
301
314
  end
315
+ return nil
302
316
  end
303
- def search_galenic_info
304
- @substances = nil
305
- @substances = @composition.split(/\s*,(?!\d|[^(]+\))\s*/u).collect { |name| ParseUtil.capitalize(name) }.uniq if @composition
306
317
 
307
- name = @name ? @name.clone : ''
308
- parts = name.split(',')
309
- form_name = nil
310
- if parts.size == 0
311
- elsif parts.size == 1
312
- @@names_without_galenic_forms << name
318
+ def handle_unknown_galform(gal_form)
319
+ return if @galenic_form
320
+ if gal_form
321
+ @galenic_form = GalenicForm.new(0, {'de' => remove_duplicated_spaces(gal_form.gsub(' +', ' '))}, @@galenic_forms[UnknownGalenicForm] )
322
+ @@new_galenic_forms << gal_form
313
323
  else
314
- parts[1..-1].each{
324
+ @galenic_form = @@galenic_forms[UnknownGalenicForm]
325
+ end
326
+ end
327
+
328
+ def search_galenic_info(gal_form)
329
+ if idx = search_exact_galform(gal_form)
330
+ return idx
331
+ end
332
+ if gal_form and gal_form.index(',')
333
+ parts = gal_form.split(/\s+|,/)
334
+ parts.each{
315
335
  |part|
316
- form_name = part.strip
317
- @galenic_form = Calc.get_galenic_form(form_name)
318
- # puts "oid #{UnknownGalenicForm} #{@galenic_form.oid} for #{name}"
319
- break unless @galenic_form.oid == UnknownGalenicForm
320
- if @galenic_form.oid == UnknownGalenicForm
321
- @galenic_form = GalenicForm.new(0, {'de' => remove_duplicated_spaces(form_name.gsub(' +', ' '))}, @@galenic_forms[UnknownGalenicForm] )
322
- @@new_galenic_forms << form_name
336
+ if idx = search_exact_galform(part)
337
+ return idx
323
338
  end
324
339
  }
325
- end
326
- @name = name.strip
327
- if @pkg_size.is_a?(Fixnum)
328
- @count = @pkg_size
329
- res = [@pkg_size]
330
- else
331
- res = @pkg_size ? @pkg_size.split(/x/i) : []
332
- if res.size >= 1
333
- @count = res[0].to_i
334
- else
335
- @count = 1
340
+ elsif gal_form
341
+ if gal_form.eql?('capsule')
342
+ idx = search_exact_galform('capsules')
343
+ return idx
336
344
  end
337
- end
338
- # check whether we find numerical and units
339
- if res.size >= 2
340
- if (result = Calc.check_for_value_and_units(res[1].strip)) != nil
341
- @multi = result[1].to_f
342
- else
343
- @multi = res[1].to_i
345
+ if idx = search_exact_galform(gal_form)
346
+ return idx
344
347
  end
345
- else
346
- @multi = 1
348
+ return nil
347
349
  end
348
- @addition = 0
349
- @scale = 1
350
- @selling_units = get_selling_units(form_name, @pkg_size, @unit)
351
350
  end
352
351
  end
353
352
  end
@@ -96,8 +96,7 @@ class CompositionParser < Parslet::Parser
96
96
  rule(:words_nested) { one_word.repeat(1) >> in_parent.maybe >> space? >> one_word.repeat(0) }
97
97
  # dose
98
98
  # 150 U.I. hFSH et 150 U.I. hLH
99
- rule(:dose_unit) {
100
- (
99
+ rule(:units) {
101
100
  str('cm²') |
102
101
  str('g/dm²') |
103
102
  str('g/l') |
@@ -118,6 +117,7 @@ class CompositionParser < Parslet::Parser
118
117
  str('kJ') |
119
118
  str('G') |
120
119
  str('g') |
120
+ str('I.E.') |
121
121
  str('l') |
122
122
  str('µl') |
123
123
  str('U. Ph. Eur.') |
@@ -146,8 +146,8 @@ class CompositionParser < Parslet::Parser
146
146
  str('% m/m') |
147
147
  str('% m/m') |
148
148
  str('%')
149
- ).as(:unit)
150
149
  }
150
+ rule(:dose_unit) { units.as(:unit) }
151
151
  rule(:qty_range) { (number >> space? >> (str('+/-') | str(' - ') | str(' -') | str('-') | str('±') ) >> space? >> number).as(:qty_range) }
152
152
  rule(:qty_unit) { dose_qty >> (space >> dose_unit).maybe }
153
153
  rule(:dose_qty) { number.as(:qty) }
@@ -434,6 +434,104 @@ class CompositionParser < Parslet::Parser
434
434
  excipiens.as(:composition) |
435
435
  space.repeat(3)
436
436
  }
437
+
437
438
  root :expression_comp
438
439
  end
439
440
 
441
+ class GalenicFormParser < CompositionParser
442
+
443
+ rule(:prepation_separator) { str(', ') | str("\n") }
444
+
445
+ rule(:prepation_name) { ((prepation_separator|lparen).absent? >> any).repeat(1)
446
+ }
447
+ rule(:dose_with_pro) {
448
+ ( match('[0-9a-zA-Z]').repeat(1) >>
449
+ str('/') >>
450
+ match('[0-9a-zA-Z\'%]').repeat(1)
451
+ ).maybe
452
+ }
453
+
454
+ rule(:gal_form) {
455
+ qty_unit_silent.maybe >>
456
+ ((( str("\n") # |
457
+ str(',') >> space? >> qty_unit_silent |
458
+ digits >> str('%')
459
+ ).absent? >> any).repeat(1) >>
460
+ (lparen >> (rparen.absent? >> any).repeat(1) >> rparen).maybe
461
+ ).as(:galenic_form) >>
462
+ space?
463
+
464
+ }
465
+
466
+ rule(:standard_galenic) {
467
+ prepation_name.as(:prepation_name) >> space? >>
468
+ prepation_separator >> space? >>
469
+ (name_without_parenthesis >> qty_unit_silent >> prepation_separator).maybe >>
470
+ (qty_unit_silent >> space?).maybe >>
471
+ (dose_with_pro >> space? >> str(',') >> space?).maybe >>
472
+ gal_form >> space?
473
+ }
474
+
475
+ rule(:qty_unit_silent) { number >> space >> units }
476
+ rule(:name_then_dose) { ((space.absent? >> any).repeat(1) >>
477
+ space >> qty_unit_silent).as(:prepation_name) >> space?.as(:galenic_form)
478
+ }
479
+
480
+ rule(:only_name) { any.repeat(1).as(:prepation_name) >> space?.as(:galenic_form)
481
+ }
482
+
483
+ rule(:name_comma_gal_form) { (space.absent? >> any).repeat(1).as(:prepation_name) >>
484
+ comma >> space >>
485
+ any.repeat(1).as(:galenic_form)
486
+ }
487
+ rule(:simple_name) { ((match(["a-zA-Z0-9,%"]) | str('-') | umlaut).repeat(1)) >>
488
+ (lparen >> (rparen.absent? >> any.repeat(1)) >> rparen).maybe
489
+ }
490
+ rule(:name_gal_form) { # e.g. Dicloabak 0,1% Augentropfen or 35 Clear-Flex 3,86 % Peritonealdialyselösung
491
+ (simple_name >> space).repeat(1).as(:prepation_name) >>
492
+ space? >>
493
+ (dose_with_pro >> space?).maybe >>
494
+ (digits.absent? >> gal_form) >> space?
495
+ }
496
+
497
+ rule(:name_without_comma_gal_form) { # Sulfure de Rhénium (186Re)-RE-186-MM-1 Cis bio International
498
+ ((str(', ')| str(',') >> match(['A-Z'])).absent? >> any).repeat(1).as(:prepation_name) >>
499
+ comma >> space? >>
500
+ gal_form >> space?
501
+ }
502
+
503
+ # Phytopharma foie et bile capsules/Leber-Galle Kapseln
504
+ rule(:leber_gallen_kapseln) { ((str('/Leber-Galle Kapseln').absent? >> any).repeat(1)).as(:prepation_name) >>
505
+ str('/') >> any.repeat(1).as(:galenic_form) >>
506
+ space?
507
+ }
508
+ # Plak-out Spray 0,1 %
509
+ rule(:plak_out_spray) { str('Plak-out Spray 0,1 %').as(:prepation_name) >>
510
+ space? >> str('dummy').maybe.as(:galenic_form) >> space?
511
+ }
512
+ rule(:galenic) {
513
+ plak_out_spray |
514
+ leber_gallen_kapseln |
515
+ standard_galenic |
516
+ name_comma_gal_form |
517
+ name_then_dose >> space? |
518
+ name_without_comma_gal_form |
519
+ name_gal_form |
520
+ only_name >> space? |
521
+ space?
522
+ }
523
+
524
+ # for debugging purposes only
525
+ rule(:galenicD) {
526
+ plak_out_spray.as(:plak_out_spray) |
527
+ leber_gallen_kapseln.as(:leber_gallen_kapseln) |
528
+ standard_galenic.as(:standard_galenic) |
529
+ name_comma_gal_form.as(:name_comma_gal_form) |
530
+ name_then_dose.as(:name_then_dose) >> space? |
531
+ name_without_comma_gal_form.as(:name_without_comma_gal_form) |
532
+ name_gal_form.as(:name_gal_form) |
533
+ only_name.as(:only_name) >> space? |
534
+ space?
535
+ }
536
+ root :galenic
537
+ end
@@ -83,6 +83,7 @@ module ParseUtil
83
83
  comps << ParseComposition.new(composition_text.split(/,|:|\(/)[0]) if comps.size == 0
84
84
  comps
85
85
  end
86
+
86
87
  end
87
88
 
88
89
  class IntLit < Struct.new(:int)
@@ -426,3 +427,46 @@ class ParseComposition
426
427
  return result
427
428
  end
428
429
  end
430
+
431
+ class GalenicFormTransformer < CompositionTransformer
432
+
433
+ rule( :preparation_name => simple(:preparation_name),
434
+ :galenic_form => simple(:preparation_name),
435
+ ) {
436
+ |dictionary|
437
+ puts "#{File.basename(__FILE__)}:#{__LINE__}: dictionary #{dictionary}" if VERBOSE_MESSAGES
438
+ binding.pry
439
+ name = dictionary[:preparation_name] ? dictionary[:preparation_name].to_s : nil
440
+ form = dictionary[:galenic_form] ? dictionary[:galenic_form].to_s : nil
441
+ # name, form
442
+ }
443
+ end
444
+
445
+ class ParseGalenicForm
446
+ def ParseGalenicForm.from_string(string)
447
+ return nil if string == nil
448
+ stripped = string.gsub(/^"|["\n]+$/, '')
449
+ return nil unless stripped
450
+ puts "ParseGalenicForm.from_string #{string}" if VERBOSE_MESSAGES # /ng-tr/.match(Socket.gethostbyname(Socket.gethostname).first)
451
+
452
+ parser = GalenicFormParser.new
453
+ transf = GalenicFormTransformer.new
454
+ begin
455
+ if defined?(RSpec)
456
+ ast = transf.apply(parser.parse_with_debug(string))
457
+ puts "#{File.basename(__FILE__)}:#{__LINE__}: ==> " if VERBOSE_MESSAGES
458
+ pp ast if VERBOSE_MESSAGES
459
+ else
460
+ ast = transf.apply(parser.parse(string))
461
+ end
462
+ rescue Parslet::ParseFailed => error
463
+ @@errorHandler.nrParsingErrors += 1
464
+ puts "#{File.basename(__FILE__)}:#{__LINE__}: failed parsing ==> #{string}"
465
+ return nil
466
+ end
467
+ return [] unless ast
468
+ form = ast[:galenic_form] ? ast[:galenic_form].to_s.sub(/^\/\s+/, '') : nil
469
+ name = ast[:prepation_name] ? ast[:prepation_name].to_s.strip : nil
470
+ return [name, form]
471
+ end
472
+ end
@@ -1,3 +1,3 @@
1
1
  module Oddb2xml
2
- VERSION = "2.0.9"
2
+ VERSION = "2.1.0"
3
3
  end