extract-tex.pl: Neue Option `-S` zur Entfernung von Schwankungsfällen.
[wortliste.git] / skripte / wortliste / extract-tex.pl
blob3ac5dcf3b36a7c476b7125ec896e44effc269cc3
1 #! /usr/bin/perl -w
3 # extract-tex.pl
5 # Dieses Perl-Skript extrahiert einfache Wortlisten aus der
6 # »wortliste«-Datenbank im Langformat (oder ähnlichen Dateien mit gleichem
7 # Dateiformat), die beispielsweise als Eingabedateien für »patgen« verwendet
8 # werden können.
10 # Aufruf:
12 # perl extract-tex.pl [Optionen...] [liste1 liste2 ...] > input.patgen
14 # Die Eingabedateien müssen in UTF-8 kodiert sein; ist keine Eingabedatei
15 # angegeben, verwendet das Skript die Standardeingabe. Beispiele:
17 # perl extract-tex.pl -l < ../wortliste > wortliste.ref.latin9
18 # perl extract-tex.pl -t ../wortliste > wortliste.trad.utf8
20 # Die Aufrufe
22 # perl extract-tex.pl -1 ...
23 # perl extract-tex.pl -t -1 ...
24 # perl extract-tex.pl -s -1 ...
26 # liefern jeweils die gleiche Ausgabe wie
28 # sprachauszug.py -l de-1996,de-1996-x-versal ...
29 # sprachauszug.py -l de-1901,de-1901-x-versal ...
30 # sprachauszug.py -l de-CH-1901,de-1901 ...
33 # Optionen
34 # --------
36 # -t
37 # -s Option »-t« wählt die traditionelle deutsche Rechtschreibung aus,
38 # Option »-s« die traditionelle (deutsch)schweizerische Rechtschreibung.
39 # Wenn weder »-s« noch »-t« gesetzt ist, wird die reformierte deutsche
40 # Rechtschreibung ausgewählt.
42 # -G Gib zusätzlich Gesangstrennstellen aus, z.B. »A-bend«, wobei
43 # Ungünstigkeitsmarker ignoriert werden.
45 # -x Ignoriere Optionen »-g«, »-u« sowie »-1« und gib die
46 # sprachspezifischen Felder unbearbeitet aus (inklusive Kommentare).
48 # -g Gib Wörter mit gewichteten Trennstellen aus. Optional kann ein
49 # ganzzahliges Argument angegeben werden: Wert 0 gibt alle gewichtete
50 # Trennstellen aus inklusive »-« (das ist der Standardwert), Wert 1 nur
51 # die Trennstellen mit der höchsten Wichtung (ohne »-«), Wert 2 die
52 # Trennstellen mit der höchsten und zweithöchsten Wichtung (ohne »-«),
53 # usw.
55 # Beachte, dass bei nahe beieinanderstehenden Trennstellen derzeit keine
56 # zusätzliche Wichtung vorgenommen wird. Beispielsweise ist in dem Wort
58 # ab<be<ru-fen
60 # die Trennung »abbe-rufen« schlecht, weil ganz nahe der optimalen
61 # Trennstelle (nach »ab«). Das Skript gibt trotzdem diese Trennstelle
62 # als zweitbeste aus.
64 # -u Verhindere die Ausgabe von Wörtern mit Markern für unerwünschte
65 # Trennungen (z.B. »An<=al-.pha=bet«). Wenn nicht gesetzt, werden als
66 # ungünstig markierte Trennstellen entfernt (z.B. »An<=alpha=bet«).
68 # -U Gib Wörter mit Nicht-ASCII-Zeichen auch in Umschrift aus (z.B.
69 # »loe-sen«, »Haen-de«). Ausgenommen davon sind Wörter mit »ß«, weil
70 # die entsprechenden Formen mit »ss« bereits in der Wortliste enthalten
71 # sind.
73 # -1 (Ziffer 1) Verhindere einbuchstabige Trennungen. Ist die Option
74 # gesetzt, wird die erste dieser Trennungen unterdrückt, falls beide
75 # Trennstellen gleichwertig sind (z.B. »eu-ro-päi-sche« statt
76 # »eu-ro-pä-i-sche«), anderenfalls bleibt die stärkere erhalten (z.B.
77 # »päd<ago-gisch« statt »pä-d<a-go-gisch«).
79 # Gesangstrennstellen sind von dieser Option nicht betroffen; es
80 # ist daher nicht sinnvoll, gleichzeitig »-G« zu verwenden.
82 # -S Entferne Schwankungsfälle (z.B. »Sta-tion« statt »Sta-ti-on«).
84 # -v Verhindere die Ausgabe von Versalformen, wo »ß« durch »ss« ersetzt
85 # ist.
87 # -l (Kleinbuchstabe L) Konvertiere die Ausgabe von UTF-8 nach latin-9.
89 # Wir verwenden »<<>>« statt »<>« aus Sicherheitsgründen.
90 require 5.22.0;
92 use strict;
93 use warnings;
94 use English '-no_match_vars';
95 use utf8; # String-Literals direkt als UTF-8.
96 use open qw(:std :utf8);
97 use Getopt::Long qw(:config bundling);
100 my ($opt_g, $opt_G,
101 $opt_l,
102 $opt_s, $opt_S,
103 $opt_t,
104 $opt_u, $opt_U,
105 $opt_v,
106 $opt_x,
107 $opt_1);
108 $opt_g = -1;
110 GetOptions("g:i" => \$opt_g, "G" => \$opt_G,
111 "l" => \$opt_l,
112 "s" => \$opt_s, "S" => \$opt_S,
113 "t" => \$opt_t,
114 "u" => \$opt_u, "U" => \$opt_U,
115 "v" => \$opt_v,
116 "x" => \$opt_x,
117 "1" => \$opt_1);
120 my $prog = $0;
121 $prog =~ s@.*/@@;
124 # Kodierung:
125 binmode(STDOUT, ":encoding(iso-8859-15)") if $opt_l;
128 # Einige Konstanten für reguläre Ausdrücke, um die Lesbarkeit zu
129 # erhöhen.
130 my $marker = qr/[.·<>=-]/x;
131 my $buchstabe = qr/(?: [^.·<>=-] | ch)/x;
132 my $vokal = qr/[aeiouäöüy]/x;
133 # Konsonant: nicht Vokal, aber Buchstabe.
134 my $konsonant = qr/(?! $vokal ) $buchstabe/x;
137 sub entferne_marker {
138 my $arg = shift;
139 $arg =~ s/$marker//g;
140 return $arg;
143 # Wenn Option »-U« gesetzt ist, müssen wir erkennen können, ob Wörter in
144 # Umschrift in der Wortliste existieren. Wir benutzen dafür zwei Hashes.
145 my %wortliste;
146 my %wortliste_umschrift;
148 while (<<>>) {
149 # Gebe Kommentarzeilen direkt aus, falls verlangt.
150 if (/^ \s* \#/x) {
151 print if $opt_x;
152 next;
155 chop;
157 # Isoliere Kommentare.
158 s/(\# .*) $//x;
160 my $kommentar = $1 // "";
162 # Entferne Leerzeichen aller Art.
163 s/\s+//g;
165 my @feld = split(';');
166 next if $#feld < 1;
168 # reformiert: Felder 2, 4, 5, 7
169 # traditionell: Felder 2, 3, 5, 6
170 # traditionell Schweiz: Felder 2, 3, 5, 6, 8
172 # Beachte: Feld n hat Index n-1.
173 my $zeile = "";
174 $zeile = $feld[2] if defined $feld[2]
175 && $feld[2] ne "-3-" && ($opt_t || $opt_s);
176 $zeile = $feld[3] if defined $feld[3]
177 && $feld[3] ne "-4-" && !($opt_t || $opt_s);
178 if (!$zeile) {
179 # Wir nehmen Versalformen nur dann, wenn es keine normalen Formen (in
180 # Feld 2 oder 3) gibt.
181 $zeile = $feld[4] if defined $feld[4]
182 && $feld[4] ne "-5-" && !$opt_v;
183 $zeile = $feld[5] if defined $feld[5]
184 && $feld[5] ne "-6-" && ($opt_t || $opt_s) && !$opt_v;
185 $zeile = $feld[6] if defined $feld[6]
186 && $feld[6] ne "-7-" && !($opt_t || $opt_s) && !$opt_v;
189 $zeile = $feld[7] if defined $feld[7] && $opt_s;
191 if (!$zeile) {
192 $zeile = $feld[1];
195 next if $zeile eq "-2-";
197 if (!$opt_x) {
198 # Entferne spezielle Trennungen.
199 $zeile =~ s|\{ (.*?) / .*? \}|$1|gx;
201 # Entferne Doppeldeutigkeiten.
202 $zeile =~ s|\[ (.*?) / .*? \]|entferne_marker($1)|egx;
204 # Hier der Algorithmus, um die verbliebenen Markierungen in
205 # Trennstellen aufzulösen. Die Schritte sind in der gegebenen
206 # Reihenfolge abzuarbeiten.
208 # Dieses Skript implementiert ausschließlich den morphemischen
209 # Trennstil (siehe Punkt 1), unter weiterer Anwendung der Regeln
210 # 2 bis 6.
212 # (1) Auflösung von Wahlmöglichkeiten zwischen morphemischem und
213 # syllabischem Trennstil (einer der beiden Stile muß gewählt
214 # werden). Ungünstigkeitsmarker und Gesangstrennstellen
215 # werden in diesem Schritt nicht berücksichtigt (wohl aber
216 # entfernt, wenn die entsprechende Trennstelle entfällt).
218 # (a) Die Bezeichnungen
220 # <x- und -x<
222 # sind Kurzschreibungen für
224 # {<x/x-} und {x</-x} (morphemisch/syllabisch) ,
226 # wobei »x« ein Konsonant oder »ch« ist. Diese Regel gilt
227 # nicht für die Suffixe »>x-« und »-x>«. Die
228 # Zusammensetzungen »=x-« und »-x=« werden gegenwärtig
229 # nicht beachtet, da sie in der Wortliste nicht vorkommen
230 # (Beispiel: Lö-b=au).
232 # (b) Die Bezeichnungen
234 # <i- und -i<
236 # sind Kurzschreibungen für
238 # {<i·/i-} und {·i</-i} (morphemisch/syllabisch) ,
240 # wobei »i« ein Vokal ist (einschließlich »y«). Diese
241 # Regel gilt nicht für die Suffixe »>i-« und »-i>«. Die
242 # Zusammensetzungen »=i-« und »-i=« werden gegenwärtig
243 # nicht beachtet, da sie in der Wortliste nicht vorkommen
244 # (Beispiel: Ei-se-n=a-ch-er Motorenwerke).
246 # Beispielsweise bleibt die Markierung
248 # al-ge-bra>i-sche
250 # in diesem Schritt unverändert; wegen »>« gibt es keine
251 # Wahlmöglichkeit.
253 # (2) Behandle (angehängte) ».«-Marker, falls ungünstige
254 # Trennstellen unterdrückt werden sollen.
256 # (3) Entferne Flattervokale (also Einbuchstaben-Silben), falls
257 # verlangt. Beachte, daß »ch« wie ein Buchstabe behandelt
258 # wird und auch Schwankungsfälle (».«) berücksichtigt werden.
259 # Gesangstrennstellen dagegen werden ignoriert (aber
260 # gegebenenfalls entfernt).
262 # Die folgenden beiden Regeln beziehen sich auf die
263 # Trennstellen unmittelbar vor und nach dem Flattervokal.
265 # (a) Ist eine Trennstelle »stärker« als die andere, wird die
266 # stärkere Trennstelle genommen (z.B. ist »>« stärker als
267 # »-«, »-« stärker als ».«).
269 # (b) Sind die Trennstellen gleich stark, wird die rechte
270 # Trennstelle genommen.
272 # (4) Entferne Gesangstrennstellen (»·«), falls verlangt.
273 # Beachte, daß die Markierung für Gesangstrennstellen, ähnlich
274 # Ungünstigkeitsmarkern, auch zu anderen Markern treten kann
275 # (die dann ebenfalls entfernt werden).
277 # Falls Gesangstrennstellen berücksichtigt werden sollen und
278 # Situationen wie »·x<« auftreten (wobei »x« ein Konsonant
279 # oder »ch« ist), wird die »stärkere« Trennstelle genommen.
281 # (5) Entferne restliche Schwankungsfälle, falls verlangt.
283 # (6) Alle verbliebenen Markierungen werden zu »-« aufgelöst.
286 # Beispiele:
287 # Re<s-tau-rant
288 # Re<stau-rant (1a, morphemisch)
289 # Re-stau-rant (6)
291 # Re<s-tau-rant
292 # Res-tau-rant (1a, syllabisch)
294 # Ge-r<i.a-trie
295 # Ger<i.a-trie (1a, morphemisch)
296 # Ger<ia-trie (3)
297 # Ger-ia-trie (6)
299 # Ge-r<i.a-trie
300 # Ge-ri.a-trie (1a, syllabisch)
301 # Ge-ria-trie (3)
303 # Ärz-te=i·n<.i-ti.a-ti-ve
304 # Ärz-te=i·n<.i·ti.a-ti-ve (1b, morphemisch)
305 # Ärz-te=i·ni·ti.a-ti-ve (2)
306 # Ärz-te=i·ni·tia-ti-ve (3a)
307 # Ärz-te=initia-ti-ve (4)
308 # Ärz-te-initia-ti-ve (6)
310 # Ärz-te=i·n<.i-ti.a-ti-ve
311 # Ärz-te=i·ni-ti.a-ti-ve (1b, syllabisch)
312 # Ärz-te=i·ni-tia-ti-ve (3a)
313 # Ärz-te=ini-tia-ti-ve (4)
314 # Ärz-te-ini-tia-ti-ve (6)
316 # Di-a<s-po-ra
317 # Di·a<s-po-ra (1b, morphemisch)
318 # Di·a<spo-ra (1a)
319 # Dia<spo-ra (4)
320 # Dia-spo-ra (6)
322 # Di-a<s-po-ra
323 # Di-as-po-ra (1b, syllabisch)
325 # Kaf-ka=ken-.ner
326 # Kaf-ka=kenner (2)
327 # Kaf-ka-kenner (6)
329 # al-ge-bra>i-sche
330 # al-ge-bra>ische (3a)
331 # al-ge-bra-ische (6)
333 # Ru-i-ne
334 # Rui-ne (3b)
336 # A<·s-phalt
337 # A<·sphalt (1a, morphemisch)
338 # Asphalt (4)
340 # A<·s-phalt
341 # As-phalt (1a, syllabisch)
343 # ge-ni.al
344 # ge-nial (5)
346 # A·b<i-tur
347 # A·b<i·tur (1b, morphemisch)
348 # Ab<i·tur (4, mit Gesangstrennstellen)
349 # Ab-i-tur (6)
351 # A·b<i-tur
352 # A·bi-tur (1b, syllabisch)
353 # A-bi-tur (6, mit Gesangstrennstellen)
355 # Schritt 1a: »<x-« wird zu »<x«.
356 $zeile =~ s/< [.·]* $konsonant \K - \.*//gx;
357 # »-x<« wird zu »x<«.
358 $zeile =~ s/- \.* ($konsonant \.*) (?= <)/$1/gx;
360 # Schritt 1b: »<i-« wird zu »<i·«.
361 $zeile =~ s/(< \.* $vokal) -/$1·/gx;
362 # »-i<« wird zu »·i<«.
363 $zeile =~ s/- (\.* $vokal) (?= <)/·$1/gx;
365 # Ausgabe von Wörtern mit unerwünschten Trennungen?
366 next if $zeile =~ /\./ and $opt_u;
368 # Schritt 2: »a<.b« wird zu »ab«.
369 $zeile =~ s/[·<>=-]+ \.+//gx if !$opt_G;
371 if ($opt_1) {
372 # Schritt 3a: »a-b>c« wird zu »ab>c«.
373 $zeile =~ s/[-.]+ (?= $buchstabe [<>=] )//gx;
374 # »a<=b-c« wird zu »a<=bc«.
375 $zeile =~ s/[<>=] [·<>=]* $buchstabe \K [-.]+//gx;
377 # Schritt 3b: »a-b-c« wird zu »ab-c«.
378 $zeile =~ s/- ( $buchstabe - )/$1/gx;
381 if ($opt_1 && !$opt_G) {
382 # Schritt 3a: »a.b-c« wird zu »ab-c«.
383 $zeile =~ s/\. ( $buchstabe - )/$1/gx;
384 # »a-b.c« wird zu »a-bc«.
385 $zeile =~ s/( - $buchstabe ) \./$1/gx;
388 # Schritt 4.
389 if ($opt_G) {
390 # »a·x<c« wird zu »ax<c«.
391 $zeile =~ s/(?<! <) ·+ ( $konsonant < )/$1/gx;
393 else {
394 # »a<·b« wird zu »ab«.
395 $zeile =~ s/($buchstabe) $marker* ·+/$1/gx;
398 # Schritt 5:
399 if ($opt_S) {
400 # »a.b« wird zu »ab«.
401 $zeile =~ s/\.//gx;
403 else {
404 # »a.b« wird zu »a-b«.
405 $zeile =~ s/\./-/gx;
408 if ($opt_g > 0) {
409 # Berechne Wichtungen. Wir verwenden folgende Werte:
411 # -2 Wortteil
412 # -1 -
413 # 0 --
414 # 1 <, >
415 # 2 =
416 # 3 ==, <=, =>
417 # 4 ===, <==, ==>
418 # ..
420 # Bei mehrfachem Auftreten von »<« hat das am meisten links stehende
421 # den höchsten Rang. Bei mehrfachem Auftreten von »>« hat das am
422 # meisten rechts stehende den höchsten Rang. Beispiel:
424 # Mit<ver<ant-wort>lich>keit
425 # ^ ^
427 # Das bezieht sich auch auf Ketten mit »=>« u.ä:
429 # Ei-gen=wirt>schaft=>lich>keit
432 my $g;
433 my $m;
434 my ($r, $r_vorher);
435 my ($w, $w_vorher);
437 # Wir zerlegen mit `split' unter Beibehaltung der Begrenzer.
438 my @zerlegung = split /([<>=-]+)/, $zeile;
440 # Wir speichern Wichtung und Rang als Felder.
441 my @wichtung = (-2) x ($#zerlegung + 1);
442 my @rang = (0) x ($#zerlegung + 1);
444 # Erster Durchgang: Ermittle Wichtungswerte.
446 # Wir starten bei erstem Marker (mit Index 1).
447 foreach my $i (1 .. ($#zerlegung - 1)) {
448 # Ignoriere Nicht-Marker.
449 next if not $i % 2;
451 $m = $zerlegung[$i];
453 if ($m =~ /^-$/) {
454 $w = -1;
456 elsif ($m =~ /^--$/) {
457 $w = 0;
459 elsif ($m =~ /^[<>]$/) {
460 $w = 1;
462 elsif ($m =~ /^=$/) {
463 $w = 2;
465 elsif ($m =~ /( ==*>? | <?=*= )/x) {
466 $w = length($1) + 1;
468 else {
469 warn "Zeile $INPUT_LINE_NUMBER:"
470 . " unbekannter Marker »$m« behandelt als »-«\n";
471 $w = -1;
474 $wichtung[$i] = $w;
477 # Zweiter Durchgang: Adjustiere Wichtung von »<« und »>«.
479 # Behandle »<« von rechts nach links gehend.
480 $w_vorher = -2;
481 foreach my $i (reverse(1 .. ($#zerlegung - 1))) {
482 # Ignoriere Nicht-Marker.
483 next if not $i % 2;
485 if (index ($zerlegung[$i], "<") >= 0) {
486 # Hat der rechte Marker in einer Kette von »<« eine höhere
487 # Wichtung, wird diese übernommen.
488 $w = $wichtung[$i];
490 if ($w_vorher >= $w) {
491 $wichtung[$i] = $w_vorher;
493 else {
494 $w_vorher = $w;
497 # »-«-Marker zwischen zwei »<« ändert nicht deren Wichtung.
498 elsif ($zerlegung[$i] ne "-") {
499 $w_vorher = -2;
503 # Behandle »>« von links nach rechts gehend.
504 $w_vorher = -2;
505 foreach my $i (1 .. ($#zerlegung - 1)) {
506 # Ignoriere Nicht-Marker.
507 next if not $i % 2;
509 if (index ($zerlegung[$i], ">") >= 0) {
510 # Hat der linke Marker in einer Kette von »>« eine höhere
511 # Wichtung, wird diese übernommen.
512 $w = $wichtung[$i];
514 if ($w_vorher >= $w) {
515 $wichtung[$i] = $w_vorher;
517 else {
518 $w_vorher = $w;
521 # »-«-Marker zwischen zwei »>« ändert nicht deren Wichtung.
522 elsif ($zerlegung[$i] ne "-") {
523 $w_vorher = -2;
527 # Dritter Durchgang: Ermittle Rang von »<« und »>«.
529 # Behandle »<« von links nach rechts gehend.
530 $r = 0;
531 foreach my $i (1 .. ($#zerlegung - 1)) {
532 # Ignoriere Nicht-Marker.
533 next if not $i % 2;
535 if (index ($zerlegung[$i], "<") >= 0) {
536 $rang[$i] = $r--;
538 # »-«-Marker zwischen zwei »<« ändert nicht den Rang.
539 elsif ($zerlegung[$i] ne "-") {
540 $r = 0;
544 # Behandle »>« von rechts nach links gehend.
545 $r = 0;
546 foreach my $i (reverse(1 .. ($#zerlegung - 1))) {
547 # Ignoriere Nicht-Marker.
548 next if not $i % 2;
550 if (index ($zerlegung[$i], ">") >= 0) {
551 $rang[$i] = $r--;
553 # »-«-Marker zwischen zwei »>« ändert nicht den Rang.
554 elsif ($zerlegung[$i] ne "-") {
555 $r = 0;
559 # Sortiere Indexfeld für Marker mit absteigender Wichtung.
560 my @wichtungsindices =
561 sort {
562 # Benutze Rang für Sekundärsortierung.
563 if ($wichtung[$a] == $wichtung[$b]) {
564 -($rang[$a] <=> $rang[$b]);
566 else {
567 -($wichtung[$a] <=> $wichtung[$b]);
569 } (0 .. $#zerlegung);
571 # Entferne Trennstellen unter Berücksichtigung des Arguments von »-g«.
572 $g = 0;
573 $w_vorher = -2;
574 $r_vorher = 0;
576 foreach my $i (@wichtungsindices) {
577 # Alle Wortteile haben einen geraden Index und sind stets am Schluß
578 # von @wichtungsindices.
579 last if not $i % 2;
581 $w = $wichtung[$i];
582 $r = $rang[$i];
584 if ($w_vorher == $w) {
585 $g++ if $r_vorher != $r;
587 else {
588 $g++;
591 $w_vorher = $w;
592 $r_vorher = $r;
594 # Entferne Trennung mit zu geringer Wichtung.
595 $zerlegung[$i] = "" if $g > $opt_g || $w < 0;
598 $zeile = join '', @zerlegung;
600 elsif ($opt_g < 0) {
601 # Schritt 6.
602 $zeile =~ s/$marker+/-/g;
606 print "$zeile";
607 print " " . $kommentar if $kommentar && $opt_x;
608 print "\n";
610 # Der Schlüssel im Hash ist das ungetrennte Wort, konvertiert zu
611 # Kleinbuchstaben; Wert wird keiner gebraucht.
612 $wortliste{lc($feld[0])} = ();
614 if ($opt_U) {
615 my $orig_zeile = $zeile;
617 $zeile =~ tr[ÀàÁáÂâÃãÇçÈèÉéÊêËëÌìÍíÎîÏïÑñÒòÓóÔôÕõŠšÙùÚúÛûÝýŸÿŽž]
618 [AaAaAaAaCcEeEeEeEeIiIiIiIiNnOoOoOoOoSsUuUuUuYyYyZz];
620 $zeile =~ s/Ä/Ae/g;
621 $zeile =~ s/ä/ae/g;
622 $zeile =~ s/Å/Aa/g;
623 $zeile =~ s/å/aa/g;
624 $zeile =~ s/Æ/Ae/g;
625 $zeile =~ s/æ/Ae/g;
627 $zeile =~ s/Ö/Oe/g;
628 $zeile =~ s/ö/oe/g;
629 $zeile =~ s/Ø/Oe/g;
630 $zeile =~ s/ø/oe/g;
631 $zeile =~ s/Œ/Oe/g;
632 $zeile =~ s/œ/oe/g;
634 $zeile =~ s/Ü/Ue/g;
635 $zeile =~ s/ü/ue/g;
637 $wortliste_umschrift{lc($feld[0])} = $zeile if $orig_zeile ne $zeile;
641 if ($opt_U) {
642 # Wir geben nur Wörter aus, die nicht bereits in der originalen Wortliste
643 # existieren.
644 foreach my $wort (sort(keys %wortliste_umschrift)) {
645 my $umschrift = $wortliste_umschrift{$wort};
646 my $test = lc(entferne_marker($umschrift));
648 print "$umschrift\n" if not exists ($wortliste{$test});
652 # eof