Korrekturen nach Analyse der Trennstellenkategorisierung.
[wortliste.git] / skripte / python / wortfugen.py
blobd5a658c2242427d80c07914fbd40baf233ba7c6a
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 # wortfugen.py: Teste unkategorisierte Trennstellen auf Wortfugen
9 # ===============================================================
11 # ::
13 """Suche nach "Teilwortkandidaten" in der `Wortliste`"""
15 # .. contents::
17 # Vorspann
18 # ========
20 # Importiere Python Module::
22 import re # Funktionen und Klassen für reguläre Ausdrücke
23 import sys # sys.exit() zum Abbruch vor Ende (für Testzwecke)
24 import codecs
25 from collections import defaultdict # Wörterbuch mit Default
26 from copy import deepcopy
28 from werkzeug import WordFile, join_word, udiff
29 from analyse import read_teilwoerter, teilwoerter
30 from abgleich_teilwoerter import wortliste_to_teilwoerter
32 # sys.stdout mit UTF8 encoding.
33 sys.stdout = codecs.getwriter('UTF-8')(sys.stdout)
35 # Globale Variablen
36 # -----------------
38 # Ausgangsbasis
39 # -------------
41 # Die freie `Wortliste der deutschsprachigen Trennmustermannschaft`_
42 # ("Lembergsche Liste")::
44 wordfile = WordFile('../../wortliste') # ≅ 400 000 Einträge/Zeilen
46 # Sprachvarianten
47 # ---------------
49 # Sprach-Tag nach [BCP47]_::
51 # sprachvariante = 'de-1901' # "traditionell"
52 sprachvariante = 'de-1996' # Reformschreibung
53 # sprachvariante = 'de-x-GROSS' # ohne ß (Großbuchstaben und Kapitälchen)
54 # sprachvariante = 'de-1901-x-GROSS' # ohne ß (Schweiz oder GROSS)
55 # sprachvariante = 'de-1996-x-GROSS' # ohne ß (Schweiz oder GROSS)
56 # sprachvariante = 'de-CH-1901' # ohne ß (Schweiz) ("süssauer")
58 # Vergleichsbasis
59 # ~~~~~~~~~~~~~~~
60 # Verwende die Wortliste oder die mit ``analyse.py`` generierte Teilwortliste
61 # als Quelle der kategorisierten Trennungen::
63 use_teilwoerter = False
64 # use_teilwoerter = True
65 # use_teilwoerter = None # use spelldict
67 # Textdateien mit Wortbestandteilen
68 # ---------------------------------
70 # * Ein Wortteil/Zeile
71 # * Groß/Kleinschreibung unterschieden
72 # * Kodierung: utf8 (bis auf 'ogerman')
74 # Wörterbucher für die Rechtschreibprüfprogramme Ispell/Aspell
75 # Unterscheiden Groß-/Kleinschreibung und beinhalten auch kurze Wörter. ::
77 def wortdatei(wortfile, encoding='utf8'):
78 for line in open(wortfile):
79 yield line.rstrip().decode(encoding)
81 if use_teilwoerter is None:
82 if sprachvariante == 'de-1996':
83 spellfile = '../../spell/hunspell-%s'%sprachvariante
84 else:
85 spellfile = '../../spell/aspell-%s'%sprachvariante
87 spelldict = set(w for w in wortdatei(spellfile)
88 if len(w) > 2)
90 # print "spelldict", len(spelldict)
91 # print spelldict
92 # sys.exit()
94 # Entferne Wörter/Silben, die (fast) nie in Wortverbindungen vorkommen
95 # TODO: Solitäre aus einer Datei lesen. ::
97 for solitaer in ('baren', 'RAF'):
98 spelldict.discard(solitaer)
100 # Präfixe (auch als Präfix verwendete Partikel, Adjektive, ...)::
102 praefixe = set(w for w in wortdatei('wortteile/praefixe'))
104 # Präfixe die keine selbständigen Wörter sind::
106 vorsilben = set(w for w in wortdatei('wortteile/vorsilben'))
108 # Erstsilben: Wörter, die häufig als erste
109 # Silbe eines Wortes (aber nicht oder nur selten als Teilwörter) auftreten
110 # aber keine Vorsilben sind ::
112 erstsilben = set(w for w in wortdatei('wortteile/erstsilben'))
114 # Endsilben, die keine eigenständigen Wörter sind
115 # (nicht (nur) Endungen im morphologischen Sinne, sondern ganze Silben)::
117 endsilben = set(w for w in wortdatei('wortteile/endsilben'))
120 # Einträge der "Wortliste"
121 # ------------------------
122 # ::
124 wordfile = WordFile('../../wortliste') # ≅ 400 000 Einträge/Zeilen
125 wortliste = list(wordfile)
127 # Sammeln unbekannter Wortteile::
129 unbekannt1 = defaultdict(list)
130 unbekannt2 = defaultdict(list)
132 # Wörterbuch zum Aufsuchen der Teilwörter
133 # ---------------------------------------
135 if use_teilwoerter:
136 words = read_teilwoerter(path='teilwoerter-%s.txt'%sprachvariante)
137 words = set(words.trennvarianten.keys())
138 elif use_teilwoerter is False: # Gesamtwörter als "Teilwörter":
139 words = wortliste_to_teilwoerter(wortliste, sprachvariante)
140 words = set(words.trennvarianten.keys())
141 else:
142 words = spelldict
145 # 2. Durchlauf: Analyse
146 # =====================
148 # Durchlaufe alle Einträge::
150 wortliste_neu = deepcopy(wortliste)
152 for entry in wortliste_neu:
154 # Wort mit Trennungen in Sprachvariante::
156 wort = entry.get(sprachvariante)
157 if wort is None: # Wort existiert nicht in der Sprachvariante
158 continue
160 # Spezielle Teilwörter suchen::
162 # teile = wort.split(u'-')
163 # if teile[-1] == 'burg':
164 # print ('-'.join(teile[:-1]) + '=' + teile[-1])
165 # continue
167 if u'·' not in wort: # keine unkategorisierte Trennstelle
168 continue
170 # Trenne an unkategorisierten Trennstellen (markiert durch '·')::
172 teile = wort.split(u'·')
174 # Wortteile analysieren::
176 for i in range(1,len(teile)):
177 erstwort = u'·'.join(teile[:i])
178 zweitwort = u'·'.join(teile[i:])
180 # Key: Teilwort ohne Trennung, Groß/Kleinschreibung übertragen::
182 try:
183 erstkey = join_word(erstwort)
184 zweitkey = join_word(zweitwort)
185 except AssertionError, e: # Spezialtrennung
186 print e
187 continue
188 if wort[0].istitle():
189 zweitkey = zweitkey.title()
191 # Bearbeiten
192 # ==========
194 # Blöcke zur regelbasierten Kategorisierung.
195 # Zum Auskommentieren und Anpassen.
197 # Fugen-s o.ä. weglassen oder hinzufügen::
199 # erstkey = erstkey[:-1]
200 # erstkey = erstkey + 's'
202 # Komposita::
204 if ((erstkey in words
205 or erstkey.lower() in words
206 or erstkey.upper() in words)
207 and erstkey not in erstsilben
208 and erstkey.lower() not in vorsilben
209 and erstkey.lower() not in praefixe
211 (zweitkey in words
212 or zweitkey.lower() in words
213 or zweitkey.upper() in words)
214 and zweitkey.lower() not in endsilben
216 compound = '='.join((erstwort, zweitwort.lower()))
217 print u'%-30s %-15s %s'% (compound, erstkey,zweitkey)
218 entry.set(compound, sprachvariante)
220 # Vorsilben::
222 # if (erstkey in vorsilben
223 # # and zweitkey in words
224 # ):
225 # print str(entry), (u'%s<%s'% (erstkey,zweitwort))
226 # entry.set('-'.join((erstwort, zweitwort)), sprachvariante)
228 # Endsilben::
230 # if (erstkey in words
231 # and zweitkey.lower() in endsilben
232 # ):
233 # print str(entry), (u'%s-%s'% (erstkey,zweitwort))
234 # entry.set('-'.join((erstwort, zweitwort)), sprachvariante)
237 # # Erstsilben::
239 # if (erstkey in erstsilben or erstkey in vorsilben):
240 # print str(entry), (u'%s-%s'% (erstkey,zweitwort))
241 # entry.set('-'.join((erstwort, zweitwort)), sprachvariante)
243 # # Neueintragskandidaten::
245 # if (erstkey not in words
246 # and erstkey not in vorsilben
247 # and erstkey not in erstsilben
248 # ):
249 # unbekannt1[erstwort].append(wort)
251 # elif (zweitkey not in words
252 # and zweitkey.lower() not in endsilben
253 # ):
254 # unbekannt2[zweitwort].append(wort)
255 # else:
256 # print ("%s-%s %s" % (erstwort, zweitwort, entry))
259 # Ausgabe
260 # ==========
262 # Unbekannte Teilwörter/Silben::
264 def testausgabe(unbekannt):
265 checkliste = ['%3d %s %s' % (len(unbekannt[key]), key,
266 ','.join(unbekannt[key]))
267 for key in sorted(unbekannt.keys())]
268 checkliste.sort()
269 return u'\n'.join(checkliste) + '\n'
272 if unbekannt1:
273 print testausgabe(unbekannt1)
274 if unbekannt2:
275 print testausgabe(unbekannt2)
278 # Ein Patch für die wortliste::
280 patch = udiff(wortliste, wortliste_neu,
281 wordfile.name, wordfile.name+'-neu',
282 encoding=wordfile.encoding)
284 if patch:
285 # print patch
286 patchfile = open('wortliste.patch', 'w')
287 patchfile.write(patch + '\n')
288 else:
289 print u'keine Änderungen'