Kleine Fixes der Python-Skripte.
[wortliste.git] / skripte / python / edit_tools / umformatierung.py
blob784f321bbe0346ff1ba2dac0cdc723c80d75985a
1 #!/usr/bin/env python
2 # -*- coding: utf8 -*-
3 # :Copyright: © 2016 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 # umformatierung.py: Wandlung zwischen Lang- und Kurzformat der Wortliste(n)
9 # ==========================================================================
10 # ::
12 u"""
13 Wandlung zwischen Lang- und Kurzformat der Wortliste(n)
15 Die Eingabedateien werden in eine Liste gelesen, ggf. gewandelt, sortiert
16 und in die Standardausgabe, eine oder mehrere Dateien geschrieben.
18 Das spezielle Argument '-' steht für die Standardeingabe::
20 umformatierung.py -k wortliste > wlst
22 umformatierung.py neu.todo wlst-* > wortliste
24 Mit der Option ``--split`` kann die Aufteilung in Einzeldateien erzwungen
25 werden. Z.B. ::
27 umformatierung.py -k langeintraege --split -o wlst
29 erzeugt die Dateien ``kurz_a`` bis ``kurz_z``.
30 """
32 # ::
34 import optparse, sys, os, codecs, re
36 from wortliste import (WordEntry, ShortEntry,
37 ableitung1901, sortkey_duden)
38 from split_wortliste import split_a_z, write_a_z
41 # Wandeln einer Folge von Zeilen mit Wortliste-Einträgen
42 # vom Langformat ins Kurzformat oder (mit ``machskurz``) andersrum.
44 # >>> from umformatierung import convert_lines
45 # >>> for line in convert_lines([u'# Toll', u'Diens-te']): print unicode(line)
46 # # Toll
47 # Dienste;-2-;Dien-ste;Diens-te
49 # Da 3-buchstabige Wörter fehlen, sollte Biß automatisch ergänzt werden
50 # >>> for line in convert_lines([u'Biss;-2-;-3-;Biss;Biss'], long2short=True):
51 # ... print unicode(line)
52 # Biss;-2-;Biss;Biss;Biss
53 # >>> for line in convert_lines([u'Biss;-2-;Biss;Biss;Biss']):
54 # ... print unicode(line)
55 # Biss;-2-;-3-;Biss;Biss
57 # Da 3-buchstabige Wörter fehlen, sollte Fuß automatisch ergänzt werden
58 # >>> for line in convert_lines([u'Fuss;-2-;-3-;-4-;Fuss'], long2short=True):
59 # ... print unicode(line)
60 # -1-;-2-;Fuss;Fuss;Fuss
61 # >>> for line in convert_lines([u'-1-;-2-;Fuss;Fuss;Fuss']):
62 # ... print unicode(line)
63 # Fuss;-2-;-3-;-4-;Fuss
66 # >>> for line in convert_lines([u'Boss;Boss # en.']): print unicode(line)
67 # Boss;Boss # en.
68 # >>> for line in convert_lines([u'Boss;Boss # en.'], long2short=True): print unicode(line)
69 # Boss;Boss # en.
71 # Alternative Langformen
72 # ----------------------
74 # Die Kurzform kann einen oder mehrere Lang-Einträge ergeben:
76 # >>> for line in convert_lines([u'Mas-se']): print unicode(line)
77 # Masse;Mas-se
78 # >>> for line in convert_lines([u'Ma-ße']): print unicode(line)
79 # Maße;Ma-ße
80 # Masse;-2-;-3-;-4-;-5-;Ma-sse;Mas-se;Mas-se
82 # Regelmäßig ableitbare Felder/Einträge werden in der Kurzform zusammengefaßt:
84 # >>> for line in convert_lines([u'Passstrasse;-2-;-3-;-4-;-5-;Pass=stra-sse;Pass=stras-se;Pass=stras-se',
85 # ... u'Passstraße;-2-;-3-;Pass=stra-ße',
86 # ... u'Paßstraße;-2-;Paß=stra-ße;-4-',
87 # ... ], long2short=True):
88 # ... print unicode(line)
89 # Pass=stra-ße
92 # In der Langform werden Alternativen in ein Feld geschrieben:
94 # >>> for line in convert_lines([u'Mas-se', u'Ma-ße']):
95 # ... print unicode(line)
96 # Masse;-2-;Mas-se;Mas-se;-5-;[Mas-se/Ma-sse];Mas-se;Mas-se
97 # Maße;Ma-ße
99 # Sind die Alternativen bereits in der Quelle, bleiben sie in der Kurzform
100 # erhalten:
102 # >>> ml = [u'Masse;-2-;Mas-se;Mas-se;-5-;Ma[-s/s-]se;Mas-se;Mas-se',
103 # ... u'Maße;Ma-ße']
104 # >>> for line in convert_lines(ml, long2short=True):
105 # ... print unicode(line)
106 # Mas-se;Mas-se;Mas-se;Ma[-s/s-]se
107 # Ma-ße;Ma-ße;-3-;-4-;-5-
109 # Zurück in die Langform:
111 # >>> for line in convert_lines([u'Mas-se;Mas-se;Mas-se;Ma[-s/s-]se',
112 # ... u'Ma-ße;Ma-ße;-3-;Ma[-s/s-]se']):
113 # ... print unicode(line)
114 # Masse;-2-;Mas-se;Mas-se;-5-;Ma[-s/s-]se;Mas-se;Mas-se
115 # Maße;Ma-ße
117 # ::
119 def convert_lines(lines, long2short=False):
121 entries_dict = {} # zum Zusammenfassen
122 entries = [] #
124 for line in lines:
125 # Dekodieren, Zeilenende entfernen
126 line = line.strip()
128 if long2short:
129 # Einlesen und Wandeln
130 # Zeilen mit nur einem Feld/Wort werden als ShortEntry
131 # (allgemeingültiges Muster) gelesen
132 if u';' in line:
133 entry = WordEntry(line)
134 key = entry.key() # Schlüssel vor dem "Wegschmeißen" holen
135 entry = ShortEntry(entry, prune=False)
136 else: # einzelnes, getrenntes Wort in "de-1996"
137 entry = ShortEntry(line)
138 key = entry.key()
140 # gemeinsamer Schlüssel für zusammengehörige (Kurz)Einträge:
141 key= key.replace(u'ß', u'ss').lower()
142 key = re.sub(ur'(.)\1\1(?=[aeiouyäöü])', ur'\1\1', key) # Kipppunkt -> Kippunkt
143 # print key, unicode(entry)
145 if key in entries_dict:
146 # print key, "schon da:"
147 # if entry[0]: # Grundeintrag:
148 # vertauschen klappt nicht: ergibt -1- in "kurzdatei"
149 # (entries_dict[key], entry) = (entry, entries_dict[key])
150 # evt. andersrum mergen:
151 # entry.merge(entries_dict[key], prune=False)
152 # entries_dict[key] = entry
153 try:
154 entries_dict[key].merge(entry, prune=False)
155 # print 'm1', unicode(entries_dict[key])
156 # print 'm2', unicode(entry)
157 except AssertionError as e:
158 # sys.stderr.write(unicode(e).encode('utf8')+'\n')
159 # sys.stderr.write(unicode(entry).encode('utf8')+'\n')
160 entries.append(entry)
161 else:
162 # Spezialfall: Paß, Fuß, ... zu kurz für die wortliste
163 # (aber: Miss, Boss, ... auch in de-1901 gültig!)
164 if (len(key) == 4 and len(entry) == 2
165 and len(ableitung1901(entry[0])) == 3
166 and not entry[1]):
167 entry.pop()
168 entries_dict[key] = entry
169 entries.append(entry)
170 else: # Kurzform -> Langform
171 for entry in ShortEntry(line).wordentries(prune=False):
172 try:
173 key = entry[0].lower()
174 except IndexError:
175 key = u'####'
176 if key and len(key) < 4:
177 continue
178 if key in entries_dict: # key schon da
179 try:
180 entries_dict[key].merge(entry, prune=False,
181 allow_alternatives=True)
182 except AssertionError as e:
183 sys.stderr.write(unicode(e).encode('utf8')+'\n')
184 # entries.append(entry)
185 else:
186 entries_dict[key] = entry
187 entries.append(entry)
189 for entry in entries:
190 entry.prune()
192 return entries
195 # Default-Aktion::
197 if __name__ == '__main__':
199 # Optionen::
201 usage = '%prog [Optionen] Eingabedatei(en) > aus \n' + __doc__
203 parser = optparse.OptionParser(usage=usage)
204 parser.add_option('-k', '--long2short',
205 help=u'vom Langformat in das Kurzformat wandeln.',
206 action="store_true", default=False)
207 parser.add_option('-o', '--outfile',
208 help=u'Ausgangsdatei, Vorgabe: - (Standardausgabe)',
209 default='-')
210 parser.add_option('-s', '--split',
211 help=u'Aufteilen in Dateien "OUTFILE_a" bis "OUTFILE_z".'
212 u'Vorgabe: False (nicht splitten)',
213 action="store_true", default=False)
214 parser.add_option('-u', '--unsorted', action='store_true', default=False,
215 help=u'Überspringe die Sortierung.')
217 (options, args) = parser.parse_args()
218 if not args:
219 parser.print_help()
221 # sys.stdout mit UTF8 encoding.
222 sys.stdout = codecs.getwriter('UTF-8')(sys.stdout)
223 # sys.stderr = codecs.getwriter('UTF-8')(sys.stderr)
225 # Einlesen in eine Liste::
227 infiles = [sys.stdin if arg=='-' else open(arg) for arg in args]
228 # verschachtelte Listen entflechten: [i for lst in lsts for i in lst]
229 lines = (line.rstrip().decode('utf-8')
230 for infile in infiles for line in infile)
232 # Wandeln::
234 entries = convert_lines(lines, long2short=options.long2short)
236 # Sortieren und Ausgeben::
238 lines = (unicode(entry)+u'\n' for entry in entries)
240 if options.split is True:
241 lists = split_a_z(lines)
242 if options.unsorted is not True:
243 for l in lists.values():
244 l.sort(key=sortkey_duden)
245 write_a_z(lists, options.outfile)
246 else:
247 if options.unsorted is not True:
248 entries.sort(key=sortkey_duden)
250 if options.outfile == '-':
251 outfile = sys.stdout
252 else:
253 outfile = codecs.open(options.outfile, 'w', encoding='utf-8')
255 output = u''.join(lines)
256 outfile.write(output)