oddb2xml 2.0.9 → 2.1.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.
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