3 # :Copyright: © 2011 Günter Milde.
4 # Released without warranty under the terms of the
5 # GNU General Public License (v. 2 or later)
8 # Versuche Trennstellen neuer Wörter aus vorhandenen zu ermitteln
9 # ===============================================================
11 # Übertragen von kategorisierten Trennstellen vorhandener Wörter
12 # auf neu aufzunehmende, ungetrennte Wörter.
14 # Erwartet eine Datei mit 1 Wort/Zeile.
15 # Pfad/Dateiname im Abschnitt Konfiguration anpassen!
17 # Schreibt eine Liste von Einträgen für die Wörter, welche durch Abgleich
18 # mit der Datenbasis getrennt werden konnten auf stdout.
20 # Die Liste kann nach ``neu.todo`` gespeichert und (nach Durchsicht) mit
21 # ``prepare_patch.py neu`` in die Wortliste eingepflegt werden.
26 from collections
import defaultdict
# Wörterbuch mit Default
27 from werkzeug
import WordFile
, WordEntry
, join_word
, toggle_case
, sortkey_duden
28 from expand_teilwoerter
import expand_wordfile
33 # Pfad zur Datei mit den neu einzutragenden Wörtern::
35 # neuwortdatei = "spell/zusatz-de-1996-aspell-compact"
36 neuwortdatei
= "spell/dehyph-exptl-MV-KorrekturenA-Z.txt"
37 # neuwortdatei = "spell/DDR.txt"
39 # Vorhandene identische Einträge aus Neueinträgen aussortieren::
46 wordfile
= WordFile('../../wortliste')
52 # Übertrag von Praefixen auf Wörter ohne Präfix::
54 def praefixabgleich(key
, praefix
, grossklein
=False):
57 praefix
= praefix
.title()
59 if not key
.startswith(join_word(praefix
)):
62 altkey
= key
[len(join_word(praefix
)):]
65 altkey
= toggle_case(altkey
)
68 altentry
= words
[altkey
]
72 entry
= WordEntry(key
)
73 # print "fundum", key, unicode(entry)
74 for wort
in altentry
[1:]:
75 if not wort
.startswith(u
'-'):
77 wort
= u
'<'.join([praefix
, wort
])
397 # Nach Länge sortieren, damit spezifischere zuerst Probiert werden:
398 praefixe
.sort(key
= len)
402 # Übertrag von Einträgen auf Wörter mit anderer Endung::
404 def endungsabgleich(key
, alt
, neu
, grossklein
=False):
406 if not key
.endswith(join_word(neu
)):
409 altkey
= key
[:-len(join_word(neu
))] + join_word(alt
)
411 altkey
= toggle_case(altkey
)
414 altentry
= words
[altkey
]
418 entry
= WordEntry(key
)
419 # print "fundum", key, unicode(entry)
420 for wort
in altentry
[1:]:
421 if not wort
.startswith(u
'-'):
423 wort
= wort
[:-len(alt
)]
426 wort
= toggle_case(wort
)
427 if join_word(wort
) != key
:
431 print u
"# Übertragungsproblem: %s -> %s (%s,%s) %s" % (
432 altkey
, key
, alt
, neu
, unicode(entry
))
435 entry
.regelaenderungen()
441 # ``(<alt>, <neu>)`` Paare von Endungen::
486 (u
'-en', u
'>bar>keit'),
502 (u
'-sten', u
's-mus'),
524 (u
'e-ren', u
'-ti-on'),
555 (u
'isch', u
'i-sche'),
579 (u
'on', u
'o-nis-mus'),
596 (u
'ph', u
'-phis-mus'),
660 # Zerlege einen String mit von vorn bis hinten wandernder Bruchstelle::
662 # >>> from abgleich_neueintraege import zerlege
663 # >>> list(zerlege(u'wolle'))
664 # [(u'w', u'olle'), (u'wo', u'lle'), (u'wol', u'le'), (u'woll', u'e')]
669 for i
in range(1, len(s
)):
672 # Zerlege Kompositum in gleichberechtigte Teile::
674 # >>> from abgleich_neueintraege import split_composits
675 # >>> from werkzeug import WordEntry
676 # >>> split_composits(WordEntry(u'Blockheizkraftwerk;Block===heiz==kraft=werk'))
677 # [u'Block', u'heiz', u'kraft', u'werk']
681 def split_composits(entry
):
682 return [w
for w
in entry
[1].split(u
'=') if w
]
684 # Zerlege String, wenn die Teile in der Wortliste vorhanden sind, setze
685 # sie neu zusammen und übernehme die Trennmarkierer:
688 def trenne_key(key
, grossklein
= False):
691 for k1
, k2
in zerlege(key
):
699 e2
= words
.get(toggle_case(k2
))
701 if len(e1
) != len(e2
):
703 e1
= [e1
[1]] * len(e2
)
705 e2
= [e2
[1]] * len(e1
)
708 entry
= WordEntry(key
)
709 for w1
, w2
in zip(e1
,e2
)[1:]:
710 if w1
.startswith(u
'-'): # empty column -2-, -3-, ...
712 elif w2
.startswith(u
'-'):
719 while (level
*sep
in w1
) or (level
*sep
in w2
):
721 wort
= (level
*sep
).join([w1
, w2
])
723 entry
.conflate_fields()
724 entries
.append(entry
)
725 # Teste auf 3-teilige Composita und entferne die Wichtung:
726 # ['Kau==zahn=weh', 'Kau=zahn=weh'] -> ['Kau=zahn=weh']
727 if len(entries
) == 2:
728 teile
= [split_composits(entry
) for entry
in entries
]
729 if teile
[0] == teile
[1]:
731 while level
*sep
in teile
[0]:
733 entries
= [entries
[0]]
734 entries
[0][1] = entries
[0][1].replace((level
+1)*sep
, level
*sep
)
738 def filter_neuliste(neuwortdatei
, words
):
740 for line
in open(neuwortdatei
):
741 line
= line
.decode('utf8').strip()
742 if line
.startswith('#'):
745 neukey
= line
.split(u
';')[0]
747 print 'vorhanden:', line
748 elif neukey
.title() in words
:
749 print 'Vorhanden:', line
750 elif neukey
.lower() in words
:
751 print 'vorhanden (kleingeschrieben):', line
756 def print_proposal(entry
):
757 proposal
= getattr(entry
, "proposal", u
'')
759 print u
' ' + unicode(entry
)
760 print u
'#' + unicode(proposal
)
764 if __name__
== '__main__':
766 # sys.stdout mit UTF8 encoding.
767 sys
.stdout
= codecs
.getwriter('UTF-8')(sys
.stdout
)
772 words
= wordfile
.asdict()
773 for line
in filter_neuliste(neuwortdatei
, words
):
777 # `Wortliste` einlesen::
779 words
= expand_wordfile(wordfile
)
781 for alt
, neu
in endungen
:
782 words
.pop(join_word(neu
), None)
784 for unwort
in [u
'Em']:
785 words
.pop(unwort
, None)
787 # # schon expandierte Liste:
788 # wordfile = WordFile('wortliste-expandiert') # + Teilwort-Entries
789 # words = wordfile.asdict()
795 # Erstellen der neuen Einträge::
797 proposals
= [WordEntry(line
.decode('utf8').strip())
798 for line
in open(neuwortdatei
)
799 if not line
.startswith('#')]
801 for newentry
in proposals
:
805 # print key, unicode(newentry)
808 # Test auf vorhandene (Teil-) Wörter:
810 entry
= words
.get(key
)
815 entry
= words
.get(key
.lower())
817 neue_grossklein
.append(entry
)
820 entry
= words
.get(key
.title())
822 neue_grossklein
.append(entry
)
827 for alt
, neu
in endungen
:
828 entry
= endungsabgleich(key
, alt
, neu
, grossklein
=False)
830 entry
.comment
= newentry
.comment
837 for alt
, neu
in endungen
:
838 entry
= endungsabgleich(key
, alt
, neu
, grossklein
=True)
840 entry
.comment
= newentry
.comment
841 neue_grossklein
.append(entry
)
849 for praefix
in praefixe
:
850 entry
= praefixabgleich(key
, praefix
, grossklein
=False)
852 entry
.comment
= newentry
.comment
856 entry
= praefixabgleich(key
, praefix
, grossklein
=True)
858 entry
.comment
= newentry
.comment
859 neue_grossklein
.append(entry
)
865 # Zerlegen und test auf Fugen::
867 entries
= trenne_key(key
, grossklein
=False)
871 entries
= trenne_key(key
, grossklein
=True)
873 neue_grossklein
.extend(entries
)
876 # Nicht gefundene Wörter::
878 rest
.append(newentry
)
880 # Mehrdeutige aussortieren::
884 doppelkeys_gleich
= defaultdict(int)
886 # doppelte keys finden:
887 for entry
in neue
+ neue_grossklein
:
888 key
= entry
[0].lower()
889 if key
in alle_neuen
:
890 if entry
== alle_neuen
[key
]:
891 doppelkeys_gleich
[key
] += 1
894 alle_neuen
[key
] = entry
896 # doppelte Einträge "verlegen":
898 eindeutige_grossklein
= []
902 key
= entry
[0].lower()
903 if key
in doppelkeys
:
904 doppelte
.append(entry
)
905 elif doppelkeys_gleich
[key
] > 0:
906 doppelkeys_gleich
[key
] -= 1
908 eindeutige
.append(entry
)
910 for entry
in neue_grossklein
:
911 key
= entry
[0].lower()
912 if key
in doppelkeys
:
913 doppelte
.append(entry
)
914 elif doppelkeys_gleich
[key
] > 0:
915 doppelkeys_gleich
[key
] -= 1
917 eindeutige_grossklein
.append(entry
)
920 # Vergleich mit Original::
923 for proposal
in proposals
:
924 key
= proposal
[0].lower()
925 newentry
= alle_neuen
.get(key
)
926 if proposal
== newentry
:
927 identische
[key
] = proposal
930 newentry
.proposal
= proposal
934 print u
'\n# identisch rekonstruiert:'
935 for entry
in sorted(identische
.values(), key
=sortkey_duden
):
938 print u
'\n# eindeutig abgeleitet'
939 for entry
in eindeutige
:
940 if entry
[0].lower() not in identische
:
941 print_proposal(entry
)
942 print u
'\n# eindeutig abgeleitet (andere Großschreibung)'
943 for entry
in eindeutige_grossklein
:
944 if entry
[0].lower() not in identische
:
945 print_proposal(entry
)
947 print u
'\n# mehrdeutig abgeleitet'
948 for entry
in doppelte
:
949 print_proposal(entry
)
955 print_proposal(entry
)