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 (Fehler bei
37 `make fugen pattern-refo` und `make suffix pattern-refo` können ignoriert
40 ² Tip: mit `abgleich_neueintraege.py --filter < neue.txt > wirklich-neue.txt`
41 können in der WORTLISTE vorhandene Wörter aussortiert werden.
43 ³ `prepare_patch.py neu` nimmt auch eine Unterscheidung nach de-1901/de-1996
44 anhand der wesentlichen Regeländerungen (-st/s-t, ck/c-k, ss/ß)
45 vor. (Schweizer Spezialitäten und andere Grenzfälle müssen per Hand
48 Für Trennungen nach traditioneller Orthographie (de-1091) müssen die
49 Musterdateinen über die Optionen angegeben werden.
52 # Doctest: Beispiel für Anwendung als Python-Module
54 # >>> from hyphenate_neueintraege import *
58 import sys
, os
, codecs
, glob
, copy
, argparse
, re
, random
60 # path for local Python modules (parent dir of this file's dir)
62 os
.path
.dirname(os
.path
.dirname(os
.path
.abspath(__file__
))))
64 # import patuse, trennstellenkategorisierung
65 from wortliste
import (WordFile
, WordEntry
, ShortEntry
,
66 sortkey_duden
, run_filters
)
67 from patuse
.hyphenation
import Hyphenator
70 # Trenne mit Hyphenator
72 # :Eingabe: ungetrenntes Wort
73 # :Ausgabe: Tupel getrennter Wörter:
75 # * kategorisierte Trennungen
76 # * getrennt mit Standard-Mustern: '=<>-' -> '-'
77 # * getrennt mit "Fugen"-Mustern: '=' -> '-'
78 # * getrennt mit "Major"-Mustern: '=<' -> '-'
79 # * getrennt mit "Suffix"-Mustern: '>' -> '-'
83 def trenne(word
, verbose
=False):
86 parts_standard
= h_standard
.split_word(word
)
87 parts_fugen
= h_fugen
.split_word(word
)
88 parts_major
= h_major
.split_word(word
)
89 parts_suffix
= h_suffix
.split_word(word
)
91 print('# standard', parts_standard
)
92 print('# fugen', parts_fugen
)
93 print('# major', parts_major
)
94 print('# suffix', parts_suffix
)
96 getrennt
= ['-'.join(parts_standard
),
97 '-'.join(parts_fugen
),
98 '-'.join(parts_major
),
99 '-'.join(parts_suffix
)]
101 parts
= [] # Liste von Silben und Trennzeichen, wird am Ende zusammengefügt.
102 p_major
= '' # zum Vergleich mit parts_major
105 # Kategorisierung der Trennstellen
106 for part_standard
in parts_standard
[:-1]:
107 parts
.append(part_standard
)
108 p_major
+= part_standard
109 p_fugen
+= part_standard
110 p_suffix
+= part_standard
111 if parts_fugen
and p_fugen
== parts_fugen
[0]:
120 elif parts_suffix
and p_suffix
== parts_suffix
[0]:
124 elif parts_major
and p_major
== parts_major
[0]:
130 parts
.append(parts_standard
[-1])
132 # Alternative Kategorisierung über Zerlegung der Teilwörter/Wortteile:
133 # word = '='.join(['<'.join([h_standard.hyphenate_word(part, '-')
134 # for part in h_major.split_word(teilwort)])
135 # for teilwort in h_fugen.split_word(word)])
136 return [''.join(parts
)] + getrennt
138 def print_proposal(entry
, verbose
=False):
139 getrennt
= getattr(entry
, "hyphenated", '')
140 if proposal
and isinstance(proposal
, ShortEntry
) or len(proposal
) > 1:
141 print(' ' + str(entry
))
142 print('# ' + getrennt
[0])
144 print('# ' + ', '.join(getrennt
))
145 # print('# ' + getrennt[-1])
150 if __name__
== '__main__':
154 # Die neuesten Pattern-Dateien, welche über die "make"-Ziele
157 # make major pattern-refo
158 # make fugen pattern-refo
159 # make suffix pattern-refo
161 # im Wurzelverzeichnis der wortliste generiert werden
162 # (--help zeigt das Erstelldatum) ::
164 # Pfad zum Wurzelverzeichnis ("../../../") unabhängig vom Arbeitsverzeichnis::
166 root_dir
= os
.path
.relpath(
167 os
.path
.dirname(os
.path
.dirname(os
.path
.dirname(os
.path
.dirname(
168 os
.path
.abspath(__file__
))))) )
171 for cat
in ('', '-major', '-fugen', '-suffix'):
172 ppath
= os
.path
.join(root_dir
, 'dehyphn-x%s/dehyphn-x%s-*.pat'%(cat
,cat
))
173 patterns
[cat
] = sorted(glob
.glob(ppath
))[-1]
175 parser
= argparse
.ArgumentParser(description
= __doc__
,
176 formatter_class
=argparse
.RawDescriptionHelpFormatter
)
177 parser
.add_argument('-p', '--patterns',
178 help='Pattern-Datei (alle Trennstellen), '
179 'Vorgabe "%s"'%patterns
[''], default
=patterns
[''])
180 parser
.add_argument('--patterns_major',
181 help='Pattern-Datei (Trennstellen an Morphemgrenzen), '
182 'Vorgabe "%s"'%patterns
['-major'],
183 default
=patterns
['-major'])
184 parser
.add_argument('--patterns_fugen',
185 help='Pattern-Datei (Trennstellen an Wortfugen), '
186 'Vorgabe "%s"'%patterns
['-fugen'],
187 default
=patterns
['-fugen'])
188 parser
.add_argument('--patterns_suffix',
189 help='Pattern-Datei (Trennstellen vor Suffixen), '
190 'Vorgabe "%s"'%patterns
['-suffix'],
191 default
=patterns
['-suffix'])
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 ("=" und "<")
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(['haupttrennstellen', 'einfach'], p_generisch
)
298 proposal
.hyphenated
.append('%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('%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('%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
)
331 print('\n## Abweichung bei major ("=" und "<")')
332 for entry
in sorted(x_major
, key
=sortkey_duden
):
333 print_proposal(entry
, args
.verbose
)
335 print('\n## Abweichung bei fugen ("=")')
336 for entry
in sorted(x_fugen
, key
=sortkey_duden
):
337 print_proposal(entry
, args
.verbose
)
339 print('\n## Abweichung bei suffix (">")')
340 for entry
in sorted(x_suffix
, key
=sortkey_duden
):
341 print_proposal(entry
, args
.verbose
)
343 print('\n## Gleiche Trennung außer ggf. Wichtung/Unterdrückung:')
344 for entry
in sorted(ok
, key
=sortkey_duden
):
345 print_proposal(entry
, args
.verbose
)
347 print('\n## Statistik')
348 # print('#', len(ok), 'gleich')
349 print('#', len(ok
), 'gleich (bis auf Wichtung/Unterdrückung)')
350 print('#', len(x_suffix
), 'Abweichung bei suffix (">")')
351 print('#', len(x_fugen
), 'Abweichung bei fugen ("=")')
352 print('#', len(x_major
), 'Abweichung bei major ("=" und "<")')
353 print('#', len(x_standard
), 'Abweichung der Standard-Trennstellen')
354 print('#', len(ungetrennt
), 'Vorgabe ohne Trennung')