3 # :Copyright: © 2014 Günter Milde.
4 # Released without warranty under the terms of the
5 # GNU General Public License (v. 2 or later)
8 # hyphenate_neueintraege.py: kategorisierte Trennung mit patgen-patterns.
9 # =======================================================================
13 """Trenne Wörter mittels "hyphenation"-Algorithmus und patgen-patterns¹.
15 Eingabe: Ein ungetrenntes Wort oder Eintrag im Wortliste-Format pro Zeile.²
17 Ausgabe: Wortliste-Einträge (Neueintrag;Neu=ein-trag)
18 ohne Unterscheidung von Sprachvarianten (!)³
21 identisch rekonstruiert
22 wenn die vorhandene Trennmarkierung der ermittelten
25 wenn die Eingabe ungetrennt ist oder eine abweichende
26 Trennmarkierung aufweist
28 Bsp: python hyphenate_neueintraege.py < missing-words.txt > neu.todo
30 ``neu.todo`` kann (nach Durchsicht!!) mit `prepare_patch.py neu`
31 in die Wortliste eingepflegt werden.³
33 ¹ Verwendet als Voreinstellung "Reformschreibungs" Pattern-Dateien, welche
34 über die "make" Ziele `make pattern-refo`, `make major pattern-refo`,
35 `make fugen pattern-refo` und `make suffix pattern-refo` im
36 Wurzelverzeichnis der Wortliste generiert werden können.
38 ² Tip: mit `filter_wortliste.py -v < neue.txt > wirklich-neue.txt`
39 können in der WORTLISTE vorhandene Wörter aussortiert werden.
41 ³ `prepare_patch.py neu` nimmt auch eine Unterscheidung nach de-1901/de-1996
42 anhand der wesentlichen Regeländerungen (-st/s-t, ck/c-k, ss/ß)
43 vor. (Schweizer Spezialitäten und andere Grenzfälle müssen per Hand
46 Für Trennungen nach traditioneller Orthographie (de-1091) müssen die
47 Musterdateinen über die Optionen angegeben werden.
50 # Doctest: Beispiel für Anwendung als Python-Module
52 # >>> from hyphenate_neueintraege import *
56 import sys
, os
, glob
, argparse
, re
, random
58 # path for local Python modules (parent dir of this file's dir)
60 os
.path
.dirname(os
.path
.dirname(os
.path
.abspath(__file__
))))
62 # import patuse, trennstellenkategorisierung
63 from wortliste
import (WordFile
, WordEntry
, ShortEntry
,
64 sortkey_duden
, run_filters
)
65 from patuse
.hyphenation
import Hyphenator
68 # Trenne mit Hyphenator
70 # :Eingabe: ungetrenntes Wort
71 # :Ausgabe: Tupel getrennter Wörter:
73 # * kategorisierte Trennungen
74 # * getrennt mit Standard-Mustern: '=<>-' -> '-'
75 # * getrennt mit "Fugen"-Mustern: '=' -> '-'
76 # * getrennt mit "Major"-Mustern: '=<>' -> '-'
77 # * getrennt mit "Suffix"-Mustern: '>' -> '-'
81 def trenne(word
, verbose
=False):
84 parts_standard
= h_standard
.split_word(word
)
85 parts_fugen
= h_fugen
.split_word(word
)
86 parts_major
= h_major
.split_word(word
)
87 parts_suffix
= h_suffix
.split_word(word
)
89 print('# standard', parts_standard
)
90 print('# fugen', parts_fugen
)
91 print('# major', parts_major
)
92 print('# suffix', parts_suffix
)
94 getrennt
= ['-'.join(parts_standard
),
95 '-'.join(parts_fugen
),
96 '-'.join(parts_major
),
97 '-'.join(parts_suffix
)]
99 parts
= [] # Liste von Silben und Trennzeichen, wird am Ende zusammengefügt.
100 p_major
= '' # zum Vergleich mit parts_major
103 # Kategorisierung der Trennstellen
104 for part_standard
in parts_standard
[:-1]:
105 parts
.append(part_standard
)
106 p_major
+= part_standard
107 p_fugen
+= part_standard
108 p_suffix
+= part_standard
109 if parts_fugen
and p_fugen
== parts_fugen
[0]:
118 elif parts_suffix
and p_suffix
== parts_suffix
[0]:
122 elif parts_major
and p_major
== parts_major
[0]:
128 parts
.append(parts_standard
[-1])
130 # Alternative Kategorisierung über Zerlegung der Teilwörter/Wortteile:
131 # word = '='.join(['<'.join([h_standard.hyphenate_word(part, '-')
132 # for part in h_major.split_word(teilwort)])
133 # for teilwort in h_fugen.split_word(word)])
134 return [''.join(parts
)] + getrennt
136 def print_proposal(entry
, verbose
=False):
137 getrennt
= getattr(entry
, "hyphenated", '')
138 if proposal
and isinstance(proposal
, ShortEntry
) or len(proposal
) > 1:
139 print(' ' + str(entry
))
140 print('# ' + getrennt
[0])
142 print('# ' + ', '.join(getrennt
))
143 # print('# ' + getrennt[-1])
148 if __name__
== '__main__':
152 # Die neuesten Pattern-Dateien, welche über die "make"-Ziele
155 # make major pattern-refo
156 # make fugen pattern-refo
157 # make suffix pattern-refo
159 # im Wurzelverzeichnis der wortliste generiert werden
160 # (--help zeigt das Erstelldatum) ::
162 # Pfad zum Wurzelverzeichnis ("../../../") unabhängig vom Arbeitsverzeichnis::
164 root_dir
= os
.path
.relpath(
165 os
.path
.dirname(os
.path
.dirname(os
.path
.dirname(os
.path
.dirname(
166 os
.path
.abspath(__file__
))))) )
169 for cat
in ('', '-major', '-fugen', '-suffix'):
170 ppath
= os
.path
.join(root_dir
, 'dehyphn-x%s/dehyphn-x%s-*.pat'%(cat
,cat
))
171 patterns
[cat
] = sorted(glob
.glob(ppath
))[-1]
173 parser
= argparse
.ArgumentParser(description
= __doc__
,
174 formatter_class
=argparse
.RawDescriptionHelpFormatter
)
175 parser
.add_argument('-p', '--patterns',
176 help='Pattern-Datei (alle Trennstellen), '
177 'Vorgabe "%s"'%patterns
[''], default
=patterns
[''])
178 parser
.add_argument('--patterns_major',
179 help='Pattern-Datei (Trennstellen an Morphemgrenzen), '
180 'Vorgabe "%s"'%patterns
['-major'],
181 default
=patterns
['-major'])
182 parser
.add_argument('--patterns_fugen',
183 help='Pattern-Datei (Trennstellen an Wortfugen), '
184 'Vorgabe "%s"'%patterns
['-fugen'],
185 default
=patterns
['-fugen'])
186 parser
.add_argument('--patterns_suffix',
187 help='Pattern-Datei (Trennstellen vor Suffixen), '
188 'Vorgabe "%s"'%patterns
['-suffix'],
189 default
=patterns
['-suffix'])
190 parser
.add_argument('-a', '--nur-abweichungen', action
='store_true',
191 help='Nur abweichende Trennungen ausgeben')
192 parser
.add_argument('-k', '--kurzformat', action
='store_true',
193 help='Eingabe ist im Kurzformat')
194 parser
.add_argument('-l', '--language', metavar
='SPRACHE',
195 help='Sprachvariante (Vorgabe: "de-1996").',
197 parser
.add_argument('-u', '--unsortiert', action
='store_true',
198 help='Ausgabe ohne Sortierung')
199 parser
.add_argument('-v', '--verbose', action
='store_true',
200 help='Zusatzinformation ausgeben')
201 parser
.add_argument('-w', '--read_probability',
202 help='Wahrscheinlichkeit mit der eine Zeile '
203 'der Eingabe gelesen wird. Vorgabe 1',
204 type=float, default
=1)
205 args
= parser
.parse_args()
209 eintragsklasse
= ShortEntry
211 eintragsklasse
= WordEntry
213 # Trenner-Instanzen::
215 h_standard
= Hyphenator(args
.patterns
)
216 h_major
= Hyphenator(args
.patterns_major
)
217 h_fugen
= Hyphenator(args
.patterns_fugen
)
218 h_suffix
= Hyphenator(args
.patterns_suffix
)
221 # Erstellen der neuen Einträge::
223 proposals
= [eintragsklasse(line
.strip())
224 for line
in sys
.stdin
225 if line
.strip() and not line
.startswith('#')
226 and (random
.random() < args
.read_probability
)]
228 if args
.read_probability
!= 1:
229 print("## Eintragsverarbeitungswahrscheinlichkeit",
230 args
.read_probability
)
232 # Trennen und ggf. unsortierte Ausgabe::
237 for proposal
in proposals
:
238 key
= proposal
.key(lang
=args
.language
)
239 getrennt
= trenne(key
)
240 # getrennt = trenne(key, verbose=args.verbose)
244 print("no hyphenation of", proposal
, getrennt
, file=sys
.stderr
)
249 # unsortierte Ausgabe
254 if isinstance(proposal
, ShortEntry
) or len(proposal
) > 1:
255 print(' ' + str(proposal
))
257 proposal
.hyphenated
= getrennt
258 results
.append(proposal
)
263 # Vergleich mit Original
265 # Abweichungen von "Proposal" (in gewählter Sprachvariante) wenn der
266 # entprechende Trennstilfilter auf Proposal angewendet wird::
268 x_standard
= [] # Abweichung der Standard-Trennstellen
269 x_major
= [] # Abweichung bei major ("=" "<" ">")
270 x_fugen
= [] # Abweichung bei fugen ("=")
271 x_suffix
= [] # Abweichung bei suffix (">")
272 ok
= [] # Keine Unterschiede bei der Trennung (bis auf Wichtung)
274 ungetrennt
= [] # Eingabe war ungetrennt
278 for proposal
in results
:
279 (wort
, standard
, fugen
, major
, suffix
) = proposal
.hyphenated
282 or (args
.kurzformat
== False and len(proposal
) == 1)):
283 ungetrennt
.append(wort
)
286 # Anwenden der Trennstile auf Proposals und Prüfen auf Übereinstimmung::
288 p_generisch
= run_filters(['morphemisch', 'standard'],
289 proposal
.get(args
.language
))
291 if standard
!= run_filters(['einfach'], p_generisch
):
292 x_standard
.append(proposal
)
295 p_major
= run_filters(['morphemgrenzen', 'einfach'], p_generisch
)
298 proposal
.hyphenated
.append('major: %s != %s'%(major
, p_major
))
299 x_major
.append(proposal
)
302 p_fugen
= re
.sub('([-<.]+=*|=*>+)', '', p_generisch
)
303 p_fugen
= run_filters(['einfach'], p_fugen
)
306 proposal
.hyphenated
.append('fugen: %s != %s'%(fugen
, p_fugen
))
307 x_fugen
.append(proposal
)
310 p_suffix
= re
.sub('[-<=.]+', '', p_generisch
)
311 if suffix
!= run_filters(['einfach'], p_suffix
):
313 proposal
.hyphenated
.append('suffix: %s != %s'%(suffix
, p_suffix
))
314 x_suffix
.append(proposal
)
323 print('\n## Trennung mit Pattern (Eingabe ohne Trennungen)')
324 for entry
in sorted(ungetrennt
, key
=sortkey_duden
):
327 print('\n## Abweichung bei Standard-Trennstellen')
328 for entry
in sorted(x_standard
, key
=sortkey_duden
):
329 print_proposal(entry
, args
.verbose
)
330 if not args
.nur_abweichungen
:
332 print('\n## Abweichung bei major ("=" "<" ">")')
333 for entry
in sorted(x_major
, key
=sortkey_duden
):
334 print_proposal(entry
, args
.verbose
)
336 print('\n## Abweichung bei fugen ("=")')
337 for entry
in sorted(x_fugen
, key
=sortkey_duden
):
338 print_proposal(entry
, args
.verbose
)
340 print('\n## Abweichung bei suffix (">")')
341 for entry
in sorted(x_suffix
, key
=sortkey_duden
):
342 print_proposal(entry
, args
.verbose
)
344 print('\n## Gleiche Trennung außer ggf. Wichtung/Unterdrückung:')
345 for entry
in sorted(ok
, key
=sortkey_duden
):
346 print_proposal(entry
, args
.verbose
)
348 print('\n## Statistik')
349 # print('#', len(ok), 'gleich')
350 print('#', len(ok
), 'gleich (evt. Unterschiede in Wichtung/Unterdrückung)')
351 print('#', len(x_suffix
), 'Abweichung bei suffix (">")')
352 print('#', len(x_fugen
), 'Abweichung bei fugen ("=")')
353 print('#', len(x_major
), 'Abweichung bei major ("=" und "<")')
354 print('#', len(x_standard
), 'Abweichung der Standard-Trennstellen')
355 print('#', len(ungetrennt
), 'Vorgabe ohne Trennung')