Vervollständige dreibuchstabige Wörter mit Eszett.
[wortliste.git] / skripte / erzeuge-wortliste.pl
blob458a0e787703d678099b65f8cfa80c3c57aef31e
1 #! /usr/bin/perl -w
3 # erzeuge-wortliste.pl
5 # Dieses Perl-Skript generiert aus einer gegebenen Liste von Wörtern, die
6 # mit Trennstellenmarkern für die reformierte Rechtschreibung versehen sind,
7 # Einträge für traditionelle deutsche und schweizerdeutsche Rechtschreibung
8 # sowie Versalformen (traditionell und reformiert) im Format der
9 # »wortliste«-Datei. Es akzeptiert zusätzlich eine Liste von Ausnahmen, die
10 # bereits im Format der »wortliste«-Datei sein müssen und durch das Skript
11 # erzeugte Einträge überschreiben, wobei das erste Feld als Schlüssel
12 # verwendet wird.
14 # Wenn man versucht, »wortliste« aus den eigenen reformierten Wortformen zu
15 # erzeugen und Ausnahmen unberücksichtigt läßt, stimmen die Resultate zu
16 # mehr als 99.95% überein.
18 # Aufruf (zur Lesbarkeit auf mehrere Zeilen aufgeteilt):
20 # perl [--debug] erzeuge-wortliste.pl \
21 # [liste1 liste2 ...] \
22 # [+ ausnahme1 ausnahme2 ...] > ausgabe
24 # Das Zeichen »+« trennt die Wortlistedateien von den Ausnahmedateien.
26 # Die Eingabedateien müssen in UTF-8 kodiert sein; als Zeilenformat wird
27 # entweder eine ein- oder zweispaltige Liste (mit »;« als Feldtrenner)
28 # akzeptiert, wobei Kommentare mit »#« beginnen und unmodifiziert ausgegeben
29 # werden. Beispiele:
31 # Beispiel;Bei<spiel # Format 1
32 # Bei<spiel # Format 2
34 # Dateiname »-« entspricht der Standardeingabe. Sind keine Eingabedateien
35 # angegeben, verwendet das Skript ebenfalls die Standardeingabe. Beispiel:
37 # perl erzeuge-wortliste.pl < reformiert > wortliste.erzeugt
39 # Die Ausgabe erfolgt unsortiert und sollte mit dem Skript »sort.py«
40 # weiterverarbeitet werden.
42 # Im folgenden Beispiel befinden sich die reformierten Einträge in den
43 # Dateien »a.reformiert«, »b.reformiert« usw.; die Ausnahmen sind in den
44 # Dateien »a.ausnahmen«, »b.ausnahmen« usw. Eine sortierte Wortliste kann
45 # mit
47 # perl erzeuge-wortliste.pl *.reformiert + *.ausnahmen \
48 # | python sort.py -d \
49 # > wortliste.komplett
51 # erzeugt werden.
53 # Option »--debug« gibt zusätzlich die vom Skript bestimmten Wortformen aus.
55 use strict;
56 use warnings;
57 use utf8; # String-Literals direkt als UTF-8.
58 use open qw(:std :utf8);
59 use feature 'unicode_strings';
60 use Getopt::Long qw(:config no_ignore_case
61 no_auto_abbrev
62 no_getopt_compat);
63 use List::MoreUtils 'first_index';
66 my $debug = "";
67 GetOptions("debug" => \$debug);
70 # Analyse der Wortbestandteile
71 # ----------------------------
73 # Wir verwenden Subroutinen, um die folgenden Trennvarianten abzudecken:
75 # reformierte Rechschreibung,
76 # traditionelle Rechtschreibung,
78 # reformierte Rechtschreibung, Versalform,
79 # traditionelle Rechtschreibung, Versalform,
81 # traditionelle schweizerdeutsche Rechtschreibung.
83 # Beachte: Die Wortliste hat keine separaten Einträge für traditionelle
84 # schweizerdeutsche Versalformen; diese fallen entweder mit den
85 # traditionellen Versalformen oder den traditionellen schweizerdeutschen
86 # Formen zusammen.
88 # Beachte weiters, daß sich Einträge für reformierte und traditionelle
89 # Rechtschreibung teilweise widersprechen und daher separat behandelt werden
90 # müssen; die Einträge für traditionelle deutsche und schweizerdeutsche
91 # Rechtschreibung dagegen nicht. Aus diesem Grund ist die Wortliste für
92 # traditionelle schweizerdeutsche Rechtschreibung einfach eine Obermenge der
93 # Wortliste für die traditionelle deutsche Rechtschreibung; etwaige
94 # »Fehleinträge« der traditionellen schweizerdeutschen Rechtschreibung (z.B.
95 # »süsssauer« statt dem korrekten »süssauer«) werden nicht entfernt.
98 # Die Subroutinen modifizieren direkt das an sie übergebene Argument; die
99 # Subroutinen-Varianten mit angehängtem »_« sind für Wörter ohne
100 # Trennstellenmarker.
103 # »s-t« -> »-st« (ref. -> trad.)
104 # (ref. -> trad. versal)
105 # (ref. -> trad. schweiz.)
107 sub s_t {
108 # Kno-ten=äs-te -> Kno-ten=äste
109 # Äs-te -> Äste
110 $_[0] =~ s/(?: (?<= \W \w )
111 | (?<= ^ \w ) )
113 /st/xg;
115 # Tes[-ter=/t=er<.]ken-nung -> Te[-ster=/st=er<.]ken-nung
116 $_[0] =~ s/(?<= \w [^s] )
117 s \[ \W+
119 (.*?)
122 (.*?)
124 /[-st$1\/st$2]/xg;
126 # fas-te -> fa-ste
127 # (fass-te -> fass-te)
128 $_[0] =~ s/(?<= \w [^s] )
130 /-st/xg;
133 sub s_t_ {
134 # Nichts zu tun.
138 # »-ck« -> »{ck/k-k}« (ref. -> trad.)
139 # (ref. -> trad. versal)
140 # (ref. -> trad. schweiz.)
142 sub ck {
143 # Dru[-cker=/ck=er<.]zeug>nis -> Dru[{ck/k-k}er=/ck=er<.]zeug>nis
144 $_[0] =~ s/\[ \W+
146 (.*?)
149 (.*?)
151 /[{ck\/k-k}$1\/ck$2]/xg;
153 # He-cke -> He{ck/k-k}e
154 $_[0] =~ s/[^\w\/\[\]\{\}]+
156 /{ck\/k-k}/xg;
158 # Stau[=be-/b=e]cken -> Stau[=b/b=]e{ck/k-k}en
159 $_[0] =~ s/\[ (.*?) (.)
162 (.*?) \g{2}
165 (?= [aeiouäöüy] )
166 /[$1\/$3]${2}{ck\/k-k}/xg;
168 # Ecke -> E{ck/k-k}e
169 # Buch=ecker -> Buch=e{ck/k-k}er
170 # (Eck -> Eck)
171 # (Vier=eck -> Vier=eck)
172 # (blockt -> blockt)
173 $_[0] =~ s/(?: (?<= [^\w\/\[\]\{\}] \w )
174 | (?<= ^ \w ) )
176 (?= [aeiouäöüy] )
177 /{ck\/k-k}/xg;
180 sub ck_ {
181 # Nichts zu tun.
185 # »-ß« -> »s-s« (ref. -> ref. versal)
186 # (ref. -> trad. schweiz.)
188 sub bindestrich_ß_1 {
189 # hei-ße -> heis-se
190 $_[0] =~ s/\W+
192 /s-s/xg;
194 # äße -> äs-se
195 # auf<aßen -> auf<as-sen
196 # (auf<aß -> auf<aß)
197 # (auf<aßt -> auf<aßt)
198 $_[0] =~ s/(?: (?<= \W \w )
199 | (?<= ^ \w ) )
201 (?= [aeiouäöüy] )
202 /s-s/xg;
205 sub bindestrich_ß_1_ {
206 $_[0] =~ s/\W+
208 /ss/xg;
210 $_[0] =~ s/(?: (?<= \W \w )
211 | (?<= ^ \w ) )
213 (?= [aeiouäöüy] )
214 /ss/xg;
218 # »-ß« -> »-ss« (ref. -> trad. versal)
220 sub bindestrich_ß_2 {
221 # hei-ße -> hei-sse
222 $_[0] =~ s/-ß
223 /-ss/xg;
226 sub bindestrich_ß_2_ {
227 $_[0] =~ s/-ß
228 /ss/xg;
232 # »ß-s« -> »{ss/ss-s}« (ref. -> trad. schweiz)
234 sub ß_s {
235 # süß=sau-er -> sü{ss/s=s}au-er
236 # (Süß=stoff -> Süß=stoff)
237 $_[0] =~ s/ß
238 (\W+)
240 (?= [aeiouäöüy] )
241 /{ss\/ss$1s}/xg;
244 sub ß_s_ {
245 $_[0] =~ s/ß
246 (\W+)
248 (?= [aeiouäöüy] )
249 /ss/xg;
253 # »ß« -> »ss« (ref. -> ref. versal)
254 # (ref. -> trad. versal)
255 # (ref. -> trad. schweiz.)
257 # Diese Regel ist nach den spezielleren ß-Regeln weiter oben anzuwenden.
259 sub ß {
260 # heiß -> heiss
261 # büß-te -> büss-te
262 $_[0] =~ s/ß
263 /ss/xg;
266 sub ß_ {
267 $_[0] =~ s/ß
268 /ss/xg;
272 # »ss-s« -> »{ss/ss-s}« (ref. -> trad. schweiz.)
274 sub ss_s {
275 # Ess=sucht -> E{ss/ss=s}sucht
276 # (Biss=spur -> Biss=spur)
277 $_[0] =~ s/ss
278 (\W+)
280 (?= [aeiouäöüy] )
281 /{ss\/ss$1s}/xg;
284 sub ss_s_ {
285 $_[0] =~ s/ss
286 (\W+)
288 (?= [aeiouäöüy] )
289 /ss/xg;
293 # »ss« -> »ß« (ref. -> trad.)
295 sub ss {
296 # biss=fest -> biß=fest
297 # esst -> eßt
298 # Hass -> Haß
299 # (Fa-desse -> Fa-desse)
300 $_[0] =~ s/ss
301 (?= (?: [b-df-hj-np-rtv-z]
302 | \W
303 | $ ) )
304 /ß/xg;
307 sub ss_ {
308 $_[0] =~ s/ss
309 (?= (?: [b-df-hj-np-rtv-z]
310 | \W
311 | $ ) )
312 /ß/xg;
316 # »xx-x« -> »{xx/xx-x}« (ref. -> trad.)
317 # (ref. -> trad. versal)
318 # (ref. -> trad. schweiz.)
320 # Buchstabe »x« ist irgendein Konsonant außer »s«.
322 sub xx_x {
323 # Bau=stoff==fir-ma -> Bau=sto{ff/ff==f}ir-ma
324 # (Griff=flä-che -> Griff=flä-che)
325 $_[0] =~ s/([b-df-hj-np-rtv-z]) \g{1} (\W+) \g{1}
326 (?= [aeiouäöüy] )
327 /{$1$1\/$1$1$2$1}/xg;
329 # Kipp=phä-no-men -> Ki{pp/pp=p}hä-no-men
330 $_[0] =~ s/([prt]) \g{1} (\W+) \g{1}
331 (?= h [aeiouäöüy] )
332 /{$1$1\/$1$1$2$1}/xg;
335 sub xx_x_ {
336 $_[0] =~ s/([b-df-hj-np-rtv-z]) \g{1} \W+ \g{1}
337 (?= [aeiouäöüy] )
338 /$1$1/xg;
340 $_[0] =~ s/([prt]) \g{1} \W+ \g{1}
341 (?= h [aeiouäöüy] )
342 /$1$1/xg;
346 sub entferne_marker {
347 # Es gilt
349 # [»Variante A«/»Variante B«] -> »Variante A«
351 # Beispiel:
353 # Dru[-cker=/ck=er<.]zeug>nis -> Dru-cker=zeug>nis
355 # Beachte, daß {.../...} bei reformierter Rechtschreibung nicht auftreten
356 # kann.
357 $_[0] =~ s/\[ (.*?) \/ .*? \]/$1/gx;
359 $_[0] =~ s/\W//g;
363 # Gebe eine Zeile aus, unter Berücksichtigung der möglichen Zeilenformate.
365 sub zeile {
366 my ($wort,
367 $ref_wort, $ref_trennung,
368 $ref_versal_wort, $ref_versal_trennung,
369 $trad_wort, $trad_trennung,
370 $trad_versal_wort, $trad_versal_trennung,
371 $trad_schweiz_wort, $trad_schweiz_trennung,
372 $kommentar) = @_;
374 # Eliminiere Wortformen, die nicht mit »wort« übereinstimmen.
375 $ref_trennung = "" if $wort ne $ref_wort;
376 $ref_versal_trennung = "" if $wort ne $ref_versal_wort;
377 $trad_trennung = "" if $wort ne $trad_wort;
378 $trad_versal_trennung = "" if $wort ne $trad_versal_wort;
379 $trad_schweiz_trennung = "" if $wort ne $trad_schweiz_wort;
381 print $wort;
382 if ($ref_trennung eq $trad_trennung
383 && length($ref_trennung)) {
384 print ";"
385 . $ref_trennung; # Feld 2
387 else {
388 print ";"
389 . "-2-"
390 . ";"
391 . (length($trad_trennung) ? $trad_trennung
392 : "-3-")
393 . ";"
394 . (length($ref_trennung) ? $ref_trennung
395 : "-4-");
397 if ($ref_trennung ne $ref_versal_trennung
398 || $trad_trennung ne $trad_versal_trennung
399 || $trad_trennung ne $trad_schweiz_trennung) {
400 if ($ref_versal_trennung eq $trad_versal_trennung
401 && ($ref_versal_trennung eq $trad_schweiz_trennung
402 || !$trad_schweiz_trennung)) {
403 if (length($ref_versal_trennung)) {
404 print ";"
405 . $ref_versal_trennung; # Feld 5
408 else {
409 print ";"
410 . "-5-"
411 . ";"
412 . (length($trad_versal_trennung) ? $trad_versal_trennung
413 : "-6-")
414 . ";"
415 . (length($ref_versal_trennung) ? $ref_versal_trennung
416 : "-7-")
417 . ";";
419 if ($trad_versal_trennung eq $trad_schweiz_trennung) {
420 print "-8-";
422 else {
423 print length($trad_schweiz_trennung) ? $trad_schweiz_trennung
424 : "-8-";
430 # Kommentare werden nur einmal für Einträge in der reformierten
431 # Schreibweise ausgegeben.
432 print " " . $kommentar if $kommentar && $wort eq $ref_wort;
434 print "\n";
438 # Hauptroutine
439 # ------------
441 # Wir geben zuerst die Wörter in den Ausnahmedateien in ein Hash.
442 my %ausnahmen;
444 # Alle Argumente nach dem »+«-Zeichen sind Ausnahmedateien.
445 my $index = first_index { $_ eq "+" } @ARGV;
446 if ($index > -1) {
447 my @listendateien = splice(@ARGV, 0, $index + 1);
449 while (<>) {
450 # Leere Zeilen und Kommentarzeilen werden ignoriert.
451 next if /^ \s* (?: $ | \# )/x;
453 # Zerlege Zeile in erstes Feld und Rest.
454 my @zeile = split(";", $_, 2);
455 $ausnahmen{$zeile[0]} = $zeile[1];
458 # Konstruiere die Argumentliste für die nächste »while«-Schleife.
459 @ARGV = @listendateien;
460 pop @ARGV;
463 while (<>) {
464 # Gebe Kommentarzeilen direkt aus.
465 if (/^ \s* \#/x) {
466 print;
467 next;
470 chop;
472 # Zerlege Zeile in ihre Bestandteile. Mögliche Formate:
474 # foobar;foo-bar # blabla
475 # foobar;foo-bar
476 # foo-bar # blabla
477 # foo-bar
479 /^ (?: \S+ ;)?
480 (\S+)
482 (\# .* )? $/x;
484 my $trennung = $1;
485 my $kommentar = defined $2 ? $2 : "";
488 # Wir konstruieren jetzt alle möglichen Wortformen - der Benutzer muß
489 # natürlich trotzdem alles kontrollieren.
491 # Die Ausgabe erfolgt unsortiert.
493 # reformierte Rechtschreibung
494 my $ref_trennung = $trennung;
496 my $ref_wort = $trennung;
497 entferne_marker($ref_wort);
499 # reformierte Rechtschreibung, Versalform
500 my $ref_versal_trennung = $trennung;
501 bindestrich_ß_1($ref_versal_trennung);
502 ß($ref_versal_trennung);
504 my $ref_versal_wort = $trennung;
505 bindestrich_ß_1_($ref_versal_wort);
506 ß_($ref_versal_wort);
507 entferne_marker($ref_versal_wort);
509 # traditionelle Rechtschreibung
510 my $trad_trennung = $trennung;
511 s_t($trad_trennung);
512 ck($trad_trennung);
513 ss($trad_trennung);
514 xx_x($trad_trennung);
516 my $trad_wort = $trennung;
517 s_t_($trad_wort);
518 ck_($trad_wort);
519 ss_($trad_wort);
520 xx_x_($trad_wort);
521 entferne_marker($trad_wort);
523 # traditionelle Rechtschreibung, Versalform
524 my $trad_versal_trennung = $trennung;
525 s_t($trad_versal_trennung);
526 ck($trad_versal_trennung);
527 bindestrich_ß_2($trad_versal_trennung);
528 ß($trad_versal_trennung);
529 xx_x($trad_versal_trennung);
531 my $trad_versal_wort = $trennung;
532 s_t_($trad_versal_wort);
533 ck_($trad_versal_wort);
534 bindestrich_ß_2_($trad_versal_wort);
535 ß_($trad_versal_wort);
536 xx_x_($trad_versal_wort);
537 entferne_marker($trad_versal_wort);
539 # traditionelle Rechtschreibung, schweizerdeutch
540 my $trad_schweiz_trennung = $trennung;
541 s_t($trad_schweiz_trennung);
542 ck($trad_schweiz_trennung);
543 bindestrich_ß_1($trad_schweiz_trennung);
544 ß_s($trad_schweiz_trennung);
545 ß($trad_schweiz_trennung);
546 ss_s($trad_schweiz_trennung);
547 xx_x($trad_schweiz_trennung);
549 my $trad_schweiz_wort = $trennung;
550 s_t_($trad_schweiz_wort);
551 ck_($trad_schweiz_wort);
552 bindestrich_ß_1_($trad_schweiz_wort);
553 ß_s_($trad_schweiz_wort);
554 ß_($trad_schweiz_wort);
555 ss_s_($trad_schweiz_wort);
556 xx_x_($trad_schweiz_wort);
557 entferne_marker($trad_schweiz_wort);
559 if ($debug) {
560 print "ref: "
561 . $ref_wort
562 . " "
563 . $ref_trennung
564 . "\n";
565 print "ref. versal: "
566 . $ref_versal_wort
567 . " "
568 . $ref_versal_trennung
569 . "\n";
570 print "trad: "
571 . $trad_wort
572 . " "
573 . $trad_trennung
574 . "\n";
575 print "trad. versal: "
576 . $trad_versal_wort
577 . " "
578 . $trad_versal_trennung
579 . "\n";
580 print "trad. schweiz: "
581 . $trad_schweiz_wort
582 . " "
583 . $trad_schweiz_trennung
584 . "\n";
585 print "->\n";
589 # Gebe Zeilen aus
590 # ---------------
592 # Wir bilden einen Hash, um Doubletten der möglichen Wortformen und
593 # Wortformen kürzer als vier Buchstaben zu entfernen.
594 my %wortformen = map { length($_) > 3 ? ($_, 1)
595 : ((), ()) }
596 ($ref_wort,
597 $ref_versal_wort,
598 $trad_wort,
599 $trad_versal_wort,
600 $trad_schweiz_wort);
602 foreach my $wort (keys %wortformen) {
603 if (defined($ausnahmen{$wort})) {
604 print $wort . ";" . $ausnahmen{$wort};
606 # Entferne Ausnahmeeintrag vom »ausnahmen«-Hash.
607 delete $ausnahmen{$wort};
609 else {
610 zeile($wort,
611 $ref_wort, $ref_trennung,
612 $ref_versal_wort, $ref_versal_trennung,
613 $trad_wort, $trad_trennung,
614 $trad_versal_wort, $trad_versal_trennung,
615 $trad_schweiz_wort, $trad_schweiz_trennung,
616 $kommentar);
622 # Abschließend geben wir die restlichen Ausnahmen aus.
623 foreach my $wort (keys %ausnahmen) {
624 print $wort . ";" . $ausnahmen{$wort};
627 # EOF