Python-Skript Update
[wortliste.git] / skripte / python / edit_tools / abgleich_neueintraege.py
blob79b02adaa94db04c875f7a4de2996da86a9154d7
1 #!/usr/bin/env python
2 # -*- coding: utf8 -*-
3 # :Copyright: © 2014 Günter Milde.
4 # Released without warranty under the terms of the
5 # GNU General Public License (v. 2 or later)
6 # :Id: $Id: $
8 # Versuche Trennstellen neuer Wörter aus vorhandenen zu ermitteln
9 # ===============================================================
11 u"""Trenne neue Wörter durch Ableitung von Einträgen der Wortliste.
13 Eingabe: 1 ungetrenntes Wort oder Eintrag im Wortliste-Format pro Zeile.
15 Ausgabe: Wortliste-Einträge (Vorschläge), sortiert nach:
16 identisch (falls Eingabe bereits Wortliste-Eintrag ist und eindeutig ist),
17 eindeutig abgeleitet
18 eindeutig abgeleitet (andere Großschreibung),
19 mehrdeutig abgeleitet,
20 Rest.
22 Bsp: python abgleich_neueintraege.py < dict-fail.txt > neu.todo
24 (``neu.todo`` kann (nach Durchsicht!!) mit `prepare_patch.py neu`
25 in die Wortliste eingepflegt werden.)
26 """
28 # ::
30 import sys, os, codecs, optparse
31 from collections import defaultdict # Wörterbuch mit Default
33 # path for local Python modules (parent dir of this file's dir)
34 sys.path.insert(0,
35 os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
36 from wortliste import WordFile, WordEntry, join_word, toggle_case, sortkey_duden
37 from expand_teilwoerter import expand_words
39 # Funktionen
40 # -----------
42 # Übertrag von Praefixen auf Wörter ohne Präfix::
44 def praefixabgleich(key, praefix, grossklein=False):
46 if key.istitle():
47 praefix = praefix.title()
49 if not key.startswith(join_word(praefix)):
50 return ''
52 altkey = key[len(join_word(praefix)):]
54 if grossklein:
55 altkey = toggle_case(altkey)
57 try:
58 altentry = words[altkey]
59 except KeyError:
60 return ''
62 entry = WordEntry(key)
63 # print "fundum", key, unicode(entry)
64 for wort in altentry[1:]:
65 if not wort.startswith(u'-'):
66 wort = wort.lower()
67 wort = u'<'.join([praefix, wort])
68 entry.append(wort)
70 return entry
72 praefixe = [u'abo',
73 u'ab',
74 u'ab<zu',
75 u'auf<zu',
76 u'aus<zu',
77 u'ein<zu',
78 u'mit<zu',
79 u'um<zu',
80 u'un-ter<zu',
81 u'weg<zu',
82 u'aber',
83 u'ad',
84 u'aero',
85 u'af-ro',
86 u'ag-ro',
87 u'al-lergo',
88 u'al-lein',
89 u'all',
90 u'als',
91 u'am-bi',
92 u'ami-no',
93 u'an-dro',
94 u'an-gio',
95 u'an-thro-po',
96 u'an-ti',
97 u'ang-lo',
98 u'an',
99 u'apo',
100 u'ar-chaeo',
101 u'ar-che',
102 u'ar-chäo',
103 u'ar-terio',
104 u'ar-thro',
105 u'asyn',
106 u'at-mo',
107 u'au-ßer',
108 u'auf',
109 u'aus',
110 u'aus<zu',
111 u'aut',
112 u'ba-ro',
113 u'bak-te-rio',
114 u'be',
115 u'bei',
116 u'ben-zo',
117 u'bi-blio',
118 u'bio',
119 u'che-mo',
120 u'chi-ro',
121 u'chlo-ro',
122 u'cho-reo',
123 u'chro-mo',
124 u'chro-no',
125 u'cy-ano',
126 u'dar',
127 u'de-ka',
128 u'de-zi',
129 u'demo',
130 u'der-ma-to',
131 u'des',
132 u'di-cho',
133 u'di-no',
134 u'dia',
135 u'dis',
136 u'dis-ko',
137 u'down',
138 u'drein',
139 u'durch',
140 u'dys',
141 u'e-tho',
142 u'ego',
143 u'ein',
144 u'elek-tro',
145 u'em-por',
146 u'emp',
147 u'en-do',
148 u'en-te-ro',
149 u'ent',
150 u'epi',
151 u'er-go',
152 u'er',
153 u'es-chato',
154 u'eth-no',
155 u'ety-mo',
156 u'ext-ro',
157 u'ex',
158 u'fe-ro',
159 u'fem-to',
160 u'fer-ro',
161 u'fo-no',
162 u'fort',
163 u'fran-ko',
164 u'für',
165 u'ga-so',
166 u'ge-gen',
167 u'ge-no',
168 u'ge-ron-to',
169 u'geo',
170 u'ge',
171 u'gi-ga',
172 u'gi-gan-to',
173 u'go-no',
174 u'gra-fo',
175 u'gra-pho',
176 u'gy-nä-ko',
177 u'he-lio',
178 u'he-te-ro',
179 u'he-xa',
180 u'hek-to',
181 u'hekt',
182 u'hemi',
183 u'her',
184 u'hier',
185 u'hin',
186 u'hin-ter',
187 u'hint',
188 u'ho-lo',
189 u'ho-mo',
190 u'ho-möo',
191 u'hoch',
192 u'hy-dro',
193 u'hy-per',
194 u'hy-po',
195 u'hym-no',
196 u'hyp-no',
197 u'hä-ma-to',
198 u'hä-mo',
199 u'ideo',
200 u'idio',
201 u'iko-no',
202 u'il',
203 u'im',
204 u'im-mu-no',
205 u'in',
206 u'in-fra',
207 u'in-ter',
208 u'in-tra',
209 u'ins',
210 u'int-ro',
211 u'io-no',
212 u'kar-dio',
213 u'kar-to',
214 u'kata',
215 u'klep-to',
216 u'kli-no',
217 u'kon',
218 u'kon-tra',
219 u'kor-re',
220 u'kos-mo',
221 u'kri-mi-no',
222 u'kri-no',
223 u'kryp-to',
224 u'leu-ko',
225 u'leuk',
226 u'le-xi-ko',
227 u'li-tho',
228 u'lim-no',
229 u'lo-go',
230 u'los',
231 u'lym-pho',
232 u'ma-gne-to',
233 u'mak-ro',
234 u'mam-mo',
235 u'me-ga',
236 u'me-lo',
237 u'me-so',
238 u'me-ta',
239 u'me-teo-ro',
240 u'me-tho-do',
241 u'mik-ro',
242 u'mil-li',
243 u'miss',
244 u'mit',
245 u'mo-no',
246 u'mor-pho',
247 u'mu-si-ko',
248 u'mul-ti',
249 u'my-co',
250 u'my-tho',
251 u'na-no',
252 u'nach',
253 u'ne-ben',
254 u'neo',
255 u'neu-ro',
256 u'neur',
257 u'nie-der',
258 u'no-wo',
259 u'non',
260 u'nost',
261 u'ob',
262 u'oben',
263 u'ober',
264 u'off',
265 u'ohn',
266 u'oli-go',
267 u'olig',
268 u'om-ni',
269 u'on-ko',
270 u'on-to',
271 u'op-to',
272 u'or-tho',
273 u'oszil-lo',
274 u'out',
275 u'over',
276 u'oxy',
277 u'ozea-no',
278 u'pa-ra',
279 u'pa-tho',
280 u'pa-tri',
281 u'pan-to',
282 u'pe-re',
283 u'pen-ta',
284 u'pet-ro',
285 u'phar-ma',
286 u'phar-ma-ko',
287 u'phi-lo',
288 u'phil',
289 u'pho-no',
290 u'pho-to',
291 u'phra-seo',
292 u'phy-lo',
293 u'phy-sio',
294 u'phy-to',
295 u'phä-no',
296 u'pneu-mo',
297 u'po-eto',
298 u'po-li-to',
299 u'po-ly',
300 u'po-ten-tio',
301 u'pro-to',
302 u'prä',
303 u'pseud',
304 u'psy-cho',
305 u'py-ro',
306 u'pä-do',
307 u'päd',
308 u'raus',
309 u're',
310 u'rein',
311 u'ret-ro',
312 u'ri-bo',
313 u'rä-to',
314 u'rück',
315 u'sa-mo',
316 u'sak-ro',
317 u'se-mi',
318 u'seis-mo',
319 u'selb',
320 u'ser-bo',
321 u'si-no',
322 u'so',
323 u'so-zio',
324 u'sou',
325 u'spek-tro',
326 u'ste-no',
327 u'ste-reo',
328 u'ste-tho',
329 u'stra-to',
330 u'su-per',
331 u'sub',
332 u'sup-ra',
333 u'sus',
334 u'syn',
335 u'ta-xo',
336 u'tau-to',
337 u'te-leo',
338 u'te-ra',
339 u'tech-no',
340 u'tele',
341 u'telo',
342 u'ter-mi-no',
343 u'tet-ra',
344 u'ther-mo',
345 u'throm-bo',
346 u'to-mo',
347 u'to-po',
348 u'to-xi-ko',
349 u'tra-gi',
350 u'trans',
351 u'tro-po',
352 u'tur-bo',
353 u'ty-po',
354 u'ul-tra',
355 u'um',
356 u'un',
357 u'un-der',
358 u'un-ter',
359 u'uni',
360 u'ur',
361 u'uro',
362 u'ver',
363 u'vi-no',
364 u'vi-ro',
365 u'vib-ra',
366 u'voll',
367 u'von',
368 u'vor',
369 u'vorn',
370 u'vul-ka-no',
371 u'weg',
372 u'wi-der',
373 u'xe-no',
374 u'xy-lo',
375 u'zen-ti',
376 u'zen-tri',
377 u'zer',
378 u'zu',
379 u'zwie',
380 u'zy-klo',
381 u'zy-to',
382 u'ägyp-to',
383 u'öko',
384 u'über',
387 # Nach Länge sortieren, damit spezifischere zuerst Probiert werden:
388 praefixe.sort(key = len)
389 praefixe.reverse()
392 # Übertrag von Einträgen auf Wörter mit anderer Endung::
394 def endungsabgleich(key, alt, neu, grossklein=False):
396 if not key.endswith(join_word(neu)):
397 return None
398 OK = True
399 altkey = key[:-len(join_word(neu))] + join_word(alt)
400 if grossklein:
401 altkey = toggle_case(altkey)
403 try:
404 altentry = words[altkey]
405 except KeyError:
406 return None
408 entry = WordEntry(key)
409 # print "fundum", key, unicode(entry)
410 for wort in altentry[1:]:
411 if wort.startswith(u'-'):
412 continue
413 if not wort.endswith(neu):
414 continue
415 if alt:
416 wort = wort[:-len(alt)]
417 wort += neu
418 if grossklein:
419 wort = toggle_case(wort)
420 if join_word(wort) != key:
421 OK = False
422 entry.append(wort)
424 if OK is False:
425 print u"# Übertragungsproblem: %s -> %s (%s,%s) %s" % (
426 altkey, key, alt, neu, unicode(entry))
427 return None
428 if len(entry) == 1: # keine Übertragung möglich
429 return None
431 entry.regelaenderungen() # Sprachabgleich
432 return entry
435 # Endungen
436 # --------
437 # ``(<alt>, <neu>)`` Paare von Endungen::
439 endungen = [
440 (u'', u'-de'),
441 # (u'', u'-en'),
442 # (u'', u'-er'),
443 # (u'', u'-is-mus'),
444 # (u'', u'-ität'),
445 (u'', u'-lein'),
446 (u'', u'-ne'),
447 (u'', u'-nem'),
448 (u'', u'-nen'),
449 (u'', u'-ner'),
450 (u'', u'-sche'),
451 (u'', u'-tum'),
452 (u'', u'>ar-tig'),
453 (u'', u'>chen'),
454 (u'', u'>heit'),
455 (u'', u'>keit'),
456 (u'', u'>los'),
457 (u'', u'>schaft'),
458 (u'', u'>schaft'),
459 (u'', u'>wei-se'),
460 # (u'', u'd'),
461 # (u'', u'e'),
462 # (u'', u'e-rin'),
463 # (u'', u'er'),
464 # (u'', u'is-mus'),
465 # (u'', u'm'),
466 # (u'', u'n'),
467 # (u'', u'ner'),
468 # (u'', u'r'),
469 # (u'', u's'),
470 # (u'', u's-te'),
471 # (u'', u's-te'),
472 # (u'', u's>los'),
473 # (u'', u'st'),
474 # (u'', u't'),
475 # (u'', u't-te'),
476 (u'-al', u'a-le'),
477 (u'-an', u'a-ne'),
478 (u'-at', u'a-te'),
479 (u'-ben', u'b-ne'),
480 # (u'-che', u'ch'),
481 (u'-de', u'd'),
482 (u'-en', u'>bar>keit'),
483 # (u'-en', u'e'),
484 (u'-en', u'e-ne'),
485 (u'-er', u'e-rei'),
486 (u'-er', u'e-rin'),
487 (u'-ern', u'e-re'),
488 (u'-ge', u'g'),
489 (u'-gen', u'g'),
490 (u'-in', u'i-ne'),
491 (u'-on', u'o-nen'),
492 (u'-re', u'r'),
493 (u'-re', u'rt'),
494 (u'-ren', u'r-ne'),
495 (u'-ren', u'rt'),
496 (u'-sche', u'sch'),
497 (u'-sen', u's-ne'),
498 (u'-sten', u's-mus'),
499 (u'-te',u't'),
500 (u'-tern', u't-re'),
501 (u'-ös', u'ö-se'),
502 (u'a', u'ar'),
503 (u'a', u'as'),
504 (u'b', u'-be'),
505 (u'b', u'-ber'),
506 (u'bar', u't'),
507 (u'bt', u'b-te'),
508 (u'ce', u'-cen'),
509 (u'ch', u'-che'),
510 (u'ch', u'-cher'),
511 (u'ck', u'-cke'),
512 (u'ck', u'-cker'),
513 (u'd', u'-de'),
514 (u'd', u'-dem'),
515 (u'd', u'-den'),
516 (u'd', u'-der'),
517 (u'd', u'-des'),
518 (u'd', u'>heit'),
519 (u'e', u'en'),
520 (u'e-ren', u'-ti-on'),
521 (u'e-ren', u'sch'),
522 (u'el', u'le'),
523 # (u'en', u'e'),
524 (u'en', u'em'),
525 (u'en', u'en-de'),
526 (u'en', u'end'),
527 (u'en', u'er'),
528 (u'en', u'es'),
529 (u'en', u'est'),
530 (u'en', u't'),
531 (u'en', u'te'),
532 (u'en', u'us'),
533 (u'end',u'en' ),
534 # (u'er', u'e'),
535 (u'er', u'e-rei'),
536 (u'er', u'ens'),
537 (u'er', u'in'),
538 (u'er', u'ung'),
539 (u'es', u'est'),
540 (u'es', u's-te'),
541 (u'f', u'-fe'),
542 (u'f', u'-fer'),
543 (u'g', u'-ge'),
544 (u'g', u'-gen'),
545 (u'g', u'-ger'),
546 (u'g', u'-ger'),
547 (u'g', u'-ges'),
548 (u'g', u'-gung'),
549 (u'ie', u'e'),
550 (u'in', u'en'),
551 (u'isch', u'i-sche'),
552 (u'ck', u'-cke'),
553 (u'k', u'-ke'),
554 (u'k', u'-ken'),
555 (u'k', u'-ker'),
556 (u'l', u'-le'),
557 (u'l', u'-len'),
558 (u'l', u'-ler'),
559 (u'l', u'-lis-mus'),
560 (u'le', u'-ler'),
561 (u'li-che', u'tem'),
562 (u'li-che', u'ten'),
563 (u'ln', u'-le'),
564 (u'lt', u'-le'),
565 (u'm', u'-me'),
566 (u'm', u'-mer'),
567 (u'me', u'men'),
568 (u'mus', u'men'),
569 (u'mus', u'ten'),
570 (u'mus', u'tik'),
571 (u'n', u'-at'),
572 (u'n', u'-er'),
573 (u'n', u'-ne'),
574 (u'n', u'-nen'),
575 (u'on', u'o-nis-mus'),
576 (u'n', u'-nis-mus'),
577 (u'n', u'r'),
578 (u'n', u'st'),
579 (u'n', u't'),
580 (u'n',u'-ner'),
581 (u'nd',u'n'),
582 (u'ne',u'ner'),
583 # (u'ne',u'n'),
584 (u'o',u'-on'),
585 (u'o',u'-os'),
586 (u'o',u'en'),
587 (u'on',u'o-nen'),
588 (u'p', u'-pe'),
589 (u'p', u'-pen'),
590 (u'p', u'-per'),
591 (u'ph', u'-phen'),
592 (u'ph', u'-phis-mus'),
593 (u'r', u'-re'),
594 (u'r', u'-rei'),
595 (u'r', u'-ren'),
596 (u'r', u'-rin'),
597 (u'r', u'-ris-mus'),
598 (u'r', u'-rung'),
599 (u're', u'ste'),
600 (u'ren', u'r-te'),
601 (u'ren', u'rst'),
602 (u'ren', u'rt'),
603 (u'rn', u'-re'),
604 (u'rn', u'-rung'),
605 (u'rn', u'-rung'),
606 (u'rt', u'-re'),
607 (u'rt', u'r-te'),
608 (u's', u''),
609 (u's', u'-se'),
610 (u's', u'-se-re'),
611 (u's', u'-se-res'),
612 (u's', u'-ser'),
613 (u's', u's-se'),
614 (u's', u's-ses'),
615 (u'sch', u'-sche'),
616 (u'sch', u'-schen'),
617 (u'sch', u'-scher'),
618 (u'st', u'-ste'),
619 (u'st', u'-sten'),
620 (u'st', u'n'),
621 (u't', u'-ba-re'),
622 (u't', u'>bar'),
623 (u't', u'-te'),
624 (u't', u'-te'),
625 (u't', u'-ten'),
626 (u't', u'-ter'),
627 (u't', u'-tes'),
628 (u't', u'-tin'),
629 (u't', u'-tis-mus'),
630 # (u't', u'e'),
631 (u't', u'n'),
632 (u't', u'st'),
633 (u'te', u'le'),
634 # (u'te', u't'),
635 (u'ten', u'mus'),
636 (u'ten', u'ren'),
637 (u'ten', u'tung'),
638 (u'ter', u'te-ren'),
639 (u'ti-on', u'tor'),
640 (u'um', u'a'),
641 (u'us', u'en'),
642 (u'v', u'-ve'),
643 (u'v', u'-ver'),
644 (u'v', u'-vis-mus'),
645 (u'-ve', u'v'),
646 (u'z', u'-ten'),
647 (u'z', u'-ze'),
648 (u'z', u'-zen'),
649 (u'z', u'-zer'),
650 (u'ß', u'-ße'),
651 (u'ß', u's-se'),
652 (u'ös', u'ö-se'),
653 (u'=öl', u'=öle'),
656 # Zerlege einen String mit von vorn bis hinten wandernder Bruchstelle::
658 # >>> from abgleich_neueintraege import zerlege
659 # >>> list(zerlege(u'wolle'))
660 # [(u'w', u'olle'), (u'wo', u'lle'), (u'wol', u'le'), (u'woll', u'e')]
662 # ::
664 def zerlege(s):
665 for i in range(1, len(s)):
666 yield s[:i], s[i:]
668 # Zerlege Kompositum in gleichberechtigte Teile::
670 # >>> from abgleich_neueintraege import split_composits
671 # >>> from edit_tools.wortliste import WordEntry
672 # >>> split_composits(WordEntry(u'Blockheizkraftwerk;Block===heiz==kraft=werk'))
673 # [u'Block', u'heiz', u'kraft', u'werk']
675 # ::
677 def split_composits(entry):
678 return [w for w in entry[1].split(u'=') if w]
680 # Zerlege String, wenn die Teile in der Wortliste vorhanden sind, setze
681 # sie neu zusammen und übernimm die Trennmarkierer:
684 def trenne_key(key, grossklein = False):
685 entries = []
686 sep = u'='
687 for k1, k2 in zerlege(key):
688 if grossklein:
689 k1 = toggle_case(k1)
690 if k1.istitle():
691 k2 = k2.title()
692 e1 = words.get(k1)
693 e2 = words.get(k2)
694 if not e2:
695 e2 = words.get(toggle_case(k2))
696 if e1 and e2:
697 # Falls ein Teil in Sprachvarianten existiert, verdopple den 2.
698 if len(e1) != len(e2):
699 if len(e1) == 2:
700 e1 = [e1[1]] * len(e2)
701 elif len(e2) == 2:
702 e2 = [e2[1]] * len(e1)
703 else:
704 continue
705 entry = WordEntry(key)
706 for w1, w2 in zip(e1,e2)[1:]:
707 if w1.startswith(u'-'): # empty column -2-, -3-, ...
708 wort = w1
709 elif w2.startswith(u'-'):
710 wort = w2
711 else:
712 if grossklein:
713 w1 = toggle_case(w1)
714 w2 = w2.lower()
715 level = 1
716 while (level*sep in w1) or (level*sep in w2):
717 level += 1
718 wort = (level*sep).join([w1, w2])
719 entry.append(wort)
720 entry.prune()
721 entries.append(entry)
722 # Teste auf 3-teilige Composita und entferne die Wichtung:
723 # ['Kau==zahn=weh', 'Kau=zahn=weh'] -> ['Kau=zahn=weh']
724 if len(entries) == 2:
725 teile = [split_composits(entry) for entry in entries]
726 if teile[0] == teile[1]:
727 level = 1
728 while level*sep in teile[0]:
729 level += 1
730 entries = [entries[0]]
731 entries[0][1] = entries[0][1].replace((level+1)*sep, level*sep)
732 return entries
734 def filter_neuliste(liste, words):
735 for line in liste:
736 line = line.decode('utf8').strip()
737 if line.startswith('#'):
738 yield line
739 continue
740 neukey = line.split(u';')[0]
741 if neukey in words:
742 # print 'vorhanden:', line
743 continue
744 if neukey.title() in words:
745 # print 'Vorhanden:', line
746 continue
747 if neukey.lower() in words:
748 # print 'vorhanden (kleingeschrieben):', line
749 continue
750 yield line
752 class SortableDict(dict):
753 """Dictionary with additional sorting methods
755 Tip: use key starting with with '_' for sorting before small letters
756 and with '~' for sorting after small letters.
758 def sortedkeys(self):
759 """Return sorted list of keys"""
760 keys = self.keys()
761 keys.sort()
762 return keys
764 def sortedvalues(self):
765 """Return list of values sorted by keys"""
766 return [self[key] for key in self.sortedkeys()]
768 def filter_ableitungen(liste):
769 words = SortableDict()
770 words['#'] = '# Ableitungen entfernt'
771 for line in liste:
772 line = line.decode('utf8').strip()
773 if line.startswith('#'):
774 words['#'] += '\n' + line
775 continue
776 key = line.split(u';')[0]
777 gibts_schon = False
778 for alt, neu in endungen:
779 altkey = key[:-len(join_word(neu))] + join_word(alt)
780 if altkey in words:
781 gibts_schon = True
782 break
783 if not gibts_schon:
784 words[key] = line
785 return words.sortedvalues()
787 def print_proposal(entry):
788 proposal = getattr(entry, "proposal", u'')
789 if proposal and len(proposal) > 1:
790 print u' ' + unicode(entry)
791 print u'#' + unicode(proposal)
792 else:
793 print unicode(entry)
796 if __name__ == '__main__':
798 # Pfad zu "../../../wortliste" unabhängig vom Arbeitsverzeichnis::
800 default_wortliste = os.path.relpath(os.path.join(
801 os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(
802 os.path.abspath(__file__))))),
803 'wortliste'))
805 # Optionen::
807 usage = '%prog [Optionen]\n' + __doc__
809 parser = optparse.OptionParser(usage=usage)
810 parser.add_option('-i', '--file', dest='wortliste',
811 help='Vergleichsdatei, Vorgabe "%s"'%default_wortliste,
812 default=default_wortliste)
813 parser.add_option('-f', '--filter', action="store_true",
814 help=u'in WORTLISTE vorhandene Wörter aussortieren',
815 default=False)
816 parser.add_option('-a', '--filter-ableitungen', action="store_true",
817 help=u'Ableitungen von Wörtern der Eingabe aussortieren',
818 default=False)
819 (options, args) = parser.parse_args()
821 # sys.stdout mit UTF8 encoding.
822 sys.stdout = codecs.getwriter('UTF-8')(sys.stdout)
824 wordfile = WordFile(options.wortliste)
826 # Filtern::
828 if options.filter:
829 words = wordfile.asdict()
830 for line in filter_neuliste(sys.stdin, words):
831 print line
832 sys.exit()
834 if options.filter_ableitungen:
835 for line in filter_ableitungen(sys.stdin):
836 print line
837 sys.exit()
839 # `Wortliste` einlesen
841 # Wörter, Teilwörter und Kombinationen (siehe expand_teilwoerter.py)
842 # entweder vom "cache", oder "live" expandiert::
844 cache = "wortliste-expandiert"
845 try:
846 cache_mtime = os.path.getmtime(cache)
847 except OSError:
848 cache_mtime = 0
850 # Umschreiben in Dictionary, Aussortieren von Abkürzungen
851 words = dict()
852 for entry in wordfile:
853 if u'Abk.' in entry.comment:
854 continue
855 words[entry[0]] = entry
857 if os.path.getmtime(options.wortliste) <= cache_mtime:
858 words.update(WordFile(cache).asdict())
859 else:
860 words.update(expand_words(words))
863 # Aussortieren von Wörtern, die zu "false positives" führen::
865 # Wörter, die oft als Endungen auftauchen:
866 for alt, neu in endungen:
867 words.pop(join_word(neu), None)
869 for unwort in [u'ei', u'Ei', u'em', u'est', u'et', u'Mc',
870 u'in', u'is', u'so', u'Tu', u'Um', u'Wa']:
871 words.pop(unwort, None)
875 # Erstellen der neuen Einträge::
877 neue = []
878 neue_grossklein = []
879 rest = []
881 proposals = [WordEntry(line.decode('utf8').strip())
882 for line in sys.stdin
883 if line.strip() and not line.startswith('#')]
885 for newentry in proposals:
886 OK = False
887 key = newentry.key()
889 # print key, unicode(newentry)
890 # continue
892 # Test auf vorhandene (Teil-) Wörter:
894 entry = words.get(key)
895 if entry:
896 neue.append(entry)
897 continue
898 # kleingeschrieben oder Großgeschrieben:
899 entry = words.get(key.lower()) or words.get(key.title())
900 if entry:
901 neue_grossklein.append(entry)
902 continue
904 # Endungsabgleich::
906 for alt, neu in endungen:
907 entry = endungsabgleich(key, alt, neu, grossklein=False)
908 if entry:
909 entry.comment = newentry.comment
910 neue.append(entry)
911 OK = True
912 # break
913 if OK:
914 continue
916 for alt, neu in endungen:
917 entry = endungsabgleich(key, alt, neu, grossklein=True)
918 if entry:
919 entry.comment = newentry.comment
920 neue_grossklein.append(entry)
921 OK = True
922 # break
923 if OK:
924 continue
926 # Präfixabgleich::
928 for praefix in praefixe:
929 entry = praefixabgleich(key, praefix, grossklein=False)
930 if entry:
931 entry.comment = newentry.comment
932 neue.append(entry)
933 OK = True
934 break
935 entry = praefixabgleich(key, praefix, grossklein=True)
936 if entry:
937 entry.comment = newentry.comment
938 neue_grossklein.append(entry)
939 OK = True
940 break
941 if OK:
942 continue
944 # Zerlegen und test auf Fugen::
946 entries = trenne_key(key, grossklein=False)
947 if entries:
948 neue.extend(entries)
949 continue
950 entries = trenne_key(key, grossklein=True)
951 if entries:
952 neue_grossklein.extend(entries)
953 continue
955 # Nicht gefundene Wörter::
957 rest.append(newentry)
959 # Mehrdeutige aussortieren::
961 alle_neuen = {}
962 doppelkeys = set()
963 doppelkeys_gleich = defaultdict(int)
965 # doppelte keys finden:
966 for entry in neue + neue_grossklein:
967 key = entry[0].lower()
968 if key in alle_neuen:
969 if entry == alle_neuen[key]:
970 doppelkeys_gleich[key] += 1
971 else:
972 doppelkeys.add(key)
973 alle_neuen[key] = entry
975 # doppelte Einträge "verlegen":
976 eindeutige = []
977 eindeutige_grossklein = []
978 doppelte = []
980 for entry in neue:
981 key = entry[0].lower()
982 if key in doppelkeys:
983 doppelte.append(entry)
984 elif doppelkeys_gleich[key] > 0:
985 doppelkeys_gleich[key] -= 1
986 else:
987 eindeutige.append(entry)
989 for entry in neue_grossklein:
990 key = entry[0].lower()
991 if key in doppelkeys:
992 doppelte.append(entry)
993 elif doppelkeys_gleich[key] > 0:
994 doppelkeys_gleich[key] -= 1
995 else:
996 eindeutige_grossklein.append(entry)
999 # Vergleich mit Original::
1001 identische = {}
1002 for proposal in proposals:
1003 key = proposal[0].lower()
1004 newentry = alle_neuen.get(key)
1005 if proposal == newentry:
1006 identische[key] = proposal
1007 else:
1008 if newentry:
1009 newentry.proposal = proposal
1011 # Ausgabe::
1013 print u'\n## identisch rekonstruiert:'
1014 for entry in sorted(identische.values(), key=sortkey_duden):
1015 print unicode(entry)
1017 print u'\n## eindeutig abgeleitet'
1018 for entry in eindeutige:
1019 if entry[0].lower() not in identische:
1020 print_proposal(entry)
1021 print u'\n## eindeutig abgeleitet (andere Großschreibung)'
1022 for entry in eindeutige_grossklein:
1023 if entry[0].lower() not in identische:
1024 print_proposal(entry)
1026 print u'\n## mehrdeutig abgeleitet'
1027 for entry in doppelte:
1028 print_proposal(entry)
1031 print u'\n## Rest'
1033 for entry in rest:
1034 print_proposal(entry)