Python-Skript Update.
[wortliste.git] / skripte / python / expand_teilwoerter.py
blobe868a54c9e86bbb28f65393865a561553ca30a1c
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 # Erweitern der Wortliste um Kombinationen von Teilwörtern
9 # ========================================================
11 # Zerlegen von Composita an den Wortfugen und Übernahme der Teile als
12 # eigenständige Einträge.
14 # >>> from expand_teilwoerter import *
16 # ::
18 import os, re, sys, codecs, copy
19 from werkzeug import (WordFile, WordEntry, join_word,
20 sprachabgleich, toggle_case)
21 # sort.py im Überverzeichnis:
22 sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
23 from sort import sortkey_duden
26 # Funktionen
27 # -----------
29 # Iterator, gibt alle geordneten Teilkombinationen zurück
31 # >>> list(multisplitter(u'test', u'='))
32 # [u'test']
34 # >>> list(multisplitter(u'a=b', u'='))
35 # [u'a', u'a=b', u'b']
37 # >>> list(multisplitter(u'a=b=c', u'='))
38 # [u'a', u'a=b', u'a=b=c', u'b', u'b=c', u'c']
40 # >>> list(multisplitter('a=b=c=d', '='))
41 # ['a', 'a=b', 'a=b=c', 'a=b=c=d', 'b', 'b=c', 'b=c=d', 'c', 'c=d', 'd']
43 # >>> list(multisplitter(u'a=b==c', u'=='))
44 # [u'a=b', u'a=b==c', u'c']
46 # >>> list(multisplitter('a=b==c=de', '=='))
47 # ['a=b', 'a=b==c=de', 'c=de']
49 # >>> list(multisplitter('a=b==c=de', '==='))
50 # ['a=b==c=de']
52 # >>> list(multisplitter('er[<st/st=]ritt', u'='))
53 # [u'er[<st/st=]ritt']
54 # >>> list(multisplitter('Schiff[=s/s=]tau', u'='))
55 # [u'Schiff[=s/s=]tau']
56 # >>> list(multisplitter('a{ll/ll=l}ie-bend', u'='))
57 # [u'a{ll/ll=l}ie-bend']
58 # >>> list(multisplitter('Be[t=t/{tt/tt=t}]uch', u'='))
59 # [u'Be[t=t/{tt/tt=t}]uch']
61 # ::
63 def multisplitter(wort, sep):
64 specials = re.findall(ur'\[.*%s.*\]|\{[^}]*%s[^}]*\}'%(sep,sep), wort)
65 for sp in specials:
66 wort = wort.replace(sp, sp.replace(sep, '*'))
67 parts = wort.split(sep)
68 length = len(parts)
69 for start in range(length):
70 for end in range(start+1, length+1):
71 part = sep.join(parts[start:end])
72 if specials:
73 part = part.replace('*', sep)
74 yield part
77 # Gib eine Liste möglicher Zerlegungen eines Kompositums zurück.
78 # Berücksichtige dabei die Bindungsstärke bis zum Level 3
79 # ("===", zur Zeit höchste Auszeichnung in der Wortliste).
81 # >>> multisplit(u'test')
82 # [u'test']
84 # >>> multisplit(u'a=b')
85 # [u'a', u'a=b', u'b']
87 # >>> multisplit(u'a=b=c')
88 # [u'a', u'a=b', u'a=b=c', u'b', u'b=c', u'c']
90 # >>> multisplit(u'a==b=c')
91 # [u'a', u'a==b=c', u'b', u'b=c', u'c']
93 # >>> multisplit(u'a==b=c==d')
94 # [u'a', u'a==b=c', u'a==b=c==d', u'b', u'b=c', u'c', u'b=c==d', u'd']
96 # >>> for w in multisplit(u'Brenn=stoff==zel-len===an<trieb'):
97 # ... print w
98 # Brenn
99 # Brenn=stoff
100 # Stoff
101 # Brenn=stoff==zel-len
102 # Zel-len
103 # Brenn=stoff==zel-len===an<trieb
104 # An<trieb
106 # ::
108 def multisplit(wort):
109 parts = []
110 for p3 in multisplitter(wort, u'==='):
111 if u'===' in p3:
112 parts.append(p3)
113 continue
114 for p2 in multisplitter(p3, u'=='):
115 if u'==' in p2:
116 parts.append(p2)
117 continue
118 for p1 in multisplitter(p2, u'='):
119 parts.append(p1)
120 if wort[:2].istitle():
121 parts = [part[0].title() + part[1:] for part in parts]
122 return parts
124 # Gib eine Liste von allen (sinnvollen) Zerlegungen eines WordEntry zurück
126 # >>> from werkzeug import WordEntry
128 # >>> split_entry(WordEntry(u'Aachen;Aa-chen'))
129 # [[u'Aachen', u'Aa-chen']]
130 # >>> aalbestand = WordEntry(u'Aalbestand;Aal=be<stand')
131 # >>> split_entry(aalbestand)
132 # [[u'Aal', u'Aal'], [u'Aalbestand', u'Aal=be<stand'], [u'Bestand', u'Be<stand']]
134 # >>> godi = WordEntry(u'Abendgottesdienste;-2-;Abend==got-tes=dien-ste;Abend==got-tes=diens-te')
135 # >>> for entry in split_entry(godi):
136 # ... print entry
137 # Abend;-2-;Abend;Abend
138 # Abendgottesdienste;-2-;Abend==got-tes=dien-ste;Abend==got-tes=diens-te
139 # Gottes;-2-;Got-tes;Got-tes
140 # Gottesdienste;-2-;Got-tes=dien-ste;Got-tes=diens-te
141 # Dienste;-2-;Dien-ste;Diens-te
143 # >>> bb = WordEntry(u'Biberbettuch;-2-;Bi-ber==be[t=t/{tt/tt=t}]uch')
144 # >>> for entry in split_entry(bb):
145 # ... print entry
146 # Biber;-2-;Bi-ber
147 # Biberbettuch;-2-;Bi-ber==be[t=t/{tt/tt=t}]uch
148 # Bettuch;-2-;Be[t=t/{tt/tt=t}]uch
150 # ::
152 def split_entry(entry):
154 entries = []
156 for col in range(1, len(entry)):
157 wort = entry[col]
158 if u'=' not in wort:
159 continue # nichts zu splitten
160 parts = multisplit(wort)
162 # Kopien des Originaleintrags erstellen
163 if not entries:
164 for part in parts:
165 entries.append(copy.copy(entry))
166 entries[-1][0] = join_word(part)
167 # Entries ausfüllen
168 for i in range(len(parts)):
169 entries[i][col] = parts[i]
171 if entries:
172 for e in entries:
173 e.conflate_fields() # Sprachabgleich
174 return entries
175 else:
176 return [entry]
178 # Gib ein Dictionary mit Einträgen der Wortliste und Teilwortkombinationen zurück:
180 def expand_wordfile(wordfile):
181 words = {} # Wörter aus der Liste
183 for entry in wordfile:
184 try:
185 entries = split_entry(entry)
186 except IndexError: # unterschiedliche Zerlegung je nach Sprache
187 # print "problematisch", unicode(entry)
188 words[entry[0].lower()] = entry
189 continue
191 for e in entries:
192 if len(entries) == 1 or e[0].lower() not in words:
193 words[e[0].lower()] = e
195 return words
197 if __name__ == '__main__':
199 # sys.stdout mit UTF8 encoding.
200 sys.stdout = codecs.getwriter('UTF-8')(sys.stdout)
202 # `Wortliste` einlesen::
204 wordfile = WordFile('../../wortliste') # ≅ 400 000 Einträge/Zeilen
206 words = expand_wordfile(wordfile)
208 print len(words), "expandiert"
210 outfile = open('wortliste-expandiert', 'w')
212 for entry in sorted(words.values(), key=sortkey_duden):
213 outfile.write(str(entry))
214 outfile.write('\n')