[Trennmuster] Entscheidungsmuster für Binnen- und Schluss-S in Frakturschriften
Guenter Milde
milde at users.sf.net
So Jan 29 21:34:48 CET 2012
Hallo Werner und alle Trennmustler,
On 27.01.12, Werner LEMBERG wrote:
> > Nach Anwendung eines Python-Skripts mit Konversionsregeln (+ einigen
> > Spezialfällen) auf die Wortliste erhalte ich für die traditionelle
> > Rechtschreibung (de-DE-1901):
> >
> > | Gesamtwortzahl (traditionelle Rechtschreibung) 417629
> > | Automatisch konvertiert 411341
> > | nur in neuer Rechtschreibung 4653
> > | Schweizer und Großschreibvarianten 8745
> > | Wichtung der Trennstellen fehlt 6280
> > | noch offen 8
> Das schaut doch ganz gut aus!
> > Der größte Teil der noch offenen Fälle kann durch Wichtung der
> > Trennstellen (z.B. mit dem SiSiSi-Algorithmus) gelöst werden.
> Das geht nur manuell, denn...
> > Gibt es schon Ansätze, SiSiSi über die Wortliste laufen zu
> > lassen?
> dies ist bereits geschehen und eingebaut.
Eventuell kann die Kombination SiSiSi + Kenntniss der (ungewichteten)
Trennstellen helfen weitere Wörter automatisch zu wichten.
> > Wie ist mit Trennungen nach übliche Vorsilben (aus-, bis-, ...) zu
> > verfahren: Haupt- oder Nebentrennstelle?
> Ich betrachte diese Trennstellen als Haupttrennstellen.
Sind dann die Nebentrennstellen nach "aus" von "aus-ba-lan-cier-tes" bis
"Aus-rei-se|wil-li-gen" als Fehler anzusehen?
> Beachte bitte, daß ich die Hauptarbeit in einen Zweig des
> git-Repositoriums investiert habe:
> > git branch
> * Keine-Haupttrennstellen-in-zweisilbigen-Wörtern
> master
> Da sind mehr Haupttrennstellen kontrolliert und ergänzt.
Leider sind die fehlenden Haupttrennstellen in zweisilbigen Wörtern für die
automatische ſ-Umstellung problematisch: Auch in zweisilbigen Wörtern muß
ein s=t st bleiben, aber ein s-t zu ſt werden.
Ich plädiere daher dafür, alle Haupttrennstellen in der Wortliste zu
markieren. Die "Herabstufung" der Trennstellen in zweisilbigen Wörtern kann
leicht mit einem Skript geschehen, die Unterscheidung nach Haupt- und
Nebentrennstellen nicht.
> > * Wörter mit identischer Schreibung ohne lang-s:
> >
> > - Wach[s/ſ]tube, As/Aſ, ...?
> Die sollten separiert werden. Derzeit:
> Wachstube;Wach[·s/s·]tu·be
> (»·« markiert ungewichtete Trennstellen).
> Mit »s« und »ſ«:
> Wachstube;Wachs=tu-be
> Wachſtube;Wach=ſtu·be
> Ein Skript, das »ſ« wieder nach »s« konvertiert, müßte solche Fälle
> finden und Trennstellen entsprechend unterbinden.
Ich schlage vor, die "Ur-Liste" in "Rundschreibung" zu belassen, da ich
denke, daß sie dann einfacher zu lesen und zu pflegen ist. (Anwender, die
die Liste in Frakturschrift betrachten/bearbeiten dürften in der
Unterzahl sein. ;-) Mitwirkende die neue Trennstellen beitragen müssen
sich dann nicht auch noch um die korrekte S-Schreibung sorgen.
Auch wenn die Konversion in s->ſ Richtung deutlich komplexer ist, läßt
sie sich auf der Basis von gewichteten Trennstellen weitgehend automatisch
erledigen. Unklare Fälle kann dann ein ſ-Experte über Ausnahmelisten und
verbesserte Ersetzungsregeln lösen.
> > * Probleme der Wortliste:
> >
> > - Trennung nach ß fehlt (?): ``Abgußsaal;-2-;Ab·gußsaal;-4-``
...
Bitte um Entschuldigung, das war ein Fehler in meiner latin1-utf-8 Konversion.
> > - Abkürzungen (Ausg, hrsg, insb msec, nsec) (Wirklich ohne Punkt
> > ins Wörterverzeichnis?)
> Ja, ohne Punkt im Wörterverzeichnis: Erstens hat der Punkt eine
> spezielle Bedeutung in der Liste (er markiert zu unterdrückende
> Trennstellen), zweitens ist es dem Trennalgorithmus egal :-)
Aber es bleibt die Frage, ob untrennbare Abkürzungen und falsch geschriebene
Maßeinheiten (nach SI ms und nicht msec) überhaupt in eine Trennmusterliste
gehören.
Für die s-ſ Liste ist dagegen die Aufnahme von z.B. "uſw" durchaus zu erwägen.
> > * Reformschreibung mit lang-s?
> Wäre durchaus möglich, aber wer braucht das?
> > Bei Interesse kann ich das Skript und die generierte Wortliste ins
> > Netz stellen oder schicken.
> Bitte schick doch das Skript an die Liste!
Gern.
Günter
#!/usr/bin/env python
# -*- coding: utf8 -*-
# :Copyright: © 2012 Günter Milde.
# :Licence: This work may be distributed and/or modified under
# the conditions of the `LaTeX Project Public License`,
# either version 1.3 of this license or (at your option)
# any later version.
# :Version: 0.1 (2012-01-25)
# ===================================================================
# s2long-s.py: Langes oder rundes S: Entscheidung nach Silbentrennung
# ===================================================================
#
# ::
"""Bestimme die Schreibung mit Rund- oder Lang-s
aus der `Wortliste der deutschsprachigen Trennmustermannschaft`.
"""
# Importe
# =======
#
# Funktionen und Klassen für reguläre Ausdrücke::
import re
# Ausgangsbasis
# =============
#
# Die freie `Wortliste der deutschsprachigen Trennmustermannschaft`_
# ("Lehmansche Liste")
#
# ::
wordfile = file('wortliste') # volle Liste (≅ 400 000 Wörter
# wordfile = file('wortliste-binnen-s') # vorsortierte Liste (≅ 200 000 Wörter)
# Trennzeichen
# ------------
#
# Die Trennzeichen der Wortliste sind
#
# == ================================================================
# \· ungewichtete Trennstellen (solche, wo noch niemand sich um die
# Gewichtung gekümmert hat)
# . unerwünschte Trennstellen (sinnverwirrend), z.B. Ur-in.stinkt
# = Haupttrennstellen
# \- Nebentrennstellen
# _ ungünstige Nebentrennstellen, z.B. Pol=ge_bie-te
# == ================================================================
#
#
# Funktionen
# ==========
#
# ſ-Regeln
# --------
#
# Siehe [wikipedia]_ und ("DDR"-) [Duden]_ (Regeln K 44,45)::
def s_ersetzen(word):
# ſ steht im Silbenanlaut und in den Verbindungen sp, st, sch::
word = re.sub(ur'^s', ur'ſ', word)
word = re.sub(ur'([·\-=.])s', ur'\1ſ', word)
word = word.replace(u'st', u'ſt')
word = word.replace(u'sp', u'ſp')
word = word.replace(u'sch', u'ſch')
# ſ steht in Digraphen::
word = word.replace(u'sh', u'ſh')
word = word.replace(u'ps', u'pſ') # ψ
word = word.replace(u'Ps', u'Pſ') # Ψ
word = word.replace(u'Csar', u'Cſar') # Cs -> Tsch (ungarisch)
word = word.replace(u'sz', u'ſz') # polnisch, ungarisch
word = re.sub(ur'([Tt])s([aeiouy])', ur'\1ſ\2', word) # ts (chinesisch)
# ſ steht im Inlaut als stimmhaftes s zwischen Vokalen::
word = re.sub(ur'([AEIOUYÄÖÜaeiouäöü])s([aeiouyäöü])', ur'\1ſ\2', word)
# ss wird zu ſſ, wenn es nicht an einer Haupttrennstelle oder im Auslaut
# steht::
word = word.replace(u's-ſ', u'ſ-ſ')
word = word.replace(u's.ſ', u'ſ.ſ')
# Ungetrenntes ss zwischen Selbstlauten, z.B. Hausse, Baisse
word = re.sub(ur'([AEIOUYÄÖÜaeiouäöü])ss([aeiouyäöü])', ur'\1ſſ\2', word)
# Spezialfälle
# ~~~~~~~~~~~~
#
# ſz im Anlaut trotz Trennung::
word = re.sub(ur'es[-·]zen', ur'eſ-zen', word) # Rekonvaleszenz, Adoleszenz
word = re.sub(ur's[-·]zil', ur'ſ-zil', word) # Os-zil-la-ti-on
word = re.sub(ur's[-·]zi-n', ur'ſ-zi-n', word) # faszinieren, Faszination
# ſ wird geschrieben, wenn der S-Laut nur scheinbar im Auslaut steht weil ein
# folgendes unbetontes e ausfällt::
# Basel, Beisel, Pilsen, drechseln, wechseln, häckseln
word = word.replace(u'Bas-ler', u'Baſ-ler')
word = word.replace(u'Pils·ner', u'Pilſ-ner')
word = word.replace(u'Pils-ner', u'Pilſ-ner')
word = word.replace(u'echs-ler', u'echſ-ler') # Dechsler, Wechsler
word = word.replace(u'äcks-ler', u'äckſ-ler') # Häcksler
# Insel (Rheininsler), zünseln (Maiszünsler)
word = word.replace(u'ins·ler', u'inſ-ler')
word = word.replace(u'ins-ler', u'inſ-ler')
word = word.replace(u'üns·ler', u'ünſ-ler')
word = word.replace(u'üns-ler', u'ünſ-ler')
# unsre, unsrige, ...
word = word.replace(u'uns-r', u'unſ-r')
# Häusl, Lisl, bissl, Glasl, Rössl
word = word.replace(u'sl', u'ſl')
word = word.replace(u'ssl', u'ſſl')
# word = re.sub(ur'sl$', ur'ſl', word)
# word = re.sub(ur'ssl$', ur'ſſl', word)
return word
# s-Regeln
# --------
#
# Test auf verbliebene Unklarheiten
#
# Wenn ein Wort "s" nur an Stellen enthält wo die Regeln rundes S vorsehen,
# ist die automatische Konversion abgeschlossen. ::
def is_complete(word):
# Ersetze s an Stellen wo es rund zu schreiben ist durch ~ und teste auf
# verbliebene Vorkommen::
# Spezialfälle mit rundem S (substrings):
spezialfaelle = [u'Dresd·ne', # Dresd·ner/Dresd·ner·in
]
for fall in spezialfaelle:
word = word.replace(fall, u'~')
# s steht am Wortende, auch in Zusammensetzungen (vor Haupttrennstellen)::
word = re.sub(ur's(=|$)', ur'~\1', word)
# Dasselbe gilt für Doppel-s (aus Fremdwörtern) in der traditionellen
# Rechtschreibung::
word = re.sub(ur'ss(=|$)', ur'~~\1', word)
# s steht am Silbenende (nach Nebentrennstellen), wenn kein p, t, z oder ſ
# folgt (in der traditionellen Schreibung, wird ſp/ſt nicht getrennt)::
# word = re.sub(ur's([·.\-][^ptzſ])', ur'~\1', word) # konservativ
word = re.sub(ur'ss?([·.\-][^zſ])', ur'~\1', word) # traditionell
# s steht vor z, nach den Vorsilben (r)aus-, dis-, konfis-,
# ple-bis-, (ergänzen)::
word = re.sub(ur'(^|[·.\-=])[Rr]?[Aa]us([·.\-=]z)', ur'\1~\2', word)
word = re.sub(ur'(^|[·.\-=])[Dd]is([·.\-=]z)', ur'\1~\2', word)
word = word.replace(u'on-fis-zie', u'on-fi~-zie')
word = word.replace(u'le-bis-z', u'le-bi~-z')
# s steht im Inlaut vor k, n, w::
word = re.sub(ur's([cknw])', ur'~\1', word)
# und suche nach übrigen Vorkommen::
return 's' not in word
# Trennzeichen entfernen
# ----------------------
#
# ::
def join_word(word):
# :{ }: Spezielle Trennungen für die traditionelle Rechtschreibung
#
# ::
if '{' in word:
word = word.replace(u'{ck/k·k}', u'ck')
word = word.replace(u'{ff/ff·f}', u'ff')
word = word.replace(u'{ll/ll·l}', u'll')
word = word.replace(u'{mm/mm·m}', u'mm')
word = word.replace(u'{nn/nn·n}', u'nn')
word = word.replace(u'{rr/rr·r}', u'rr')
# :[ ]: Trennstellen in doppeldeutigen Wörtern
#
# ::
if '[' in word:
word = word.replace(u'[cker·/ck·er.]', u'cker')
word = word.replace(u'[·cker·/ck·er.]', u'cker')
word = word.replace(u'[ll·/ll]', u'll')
word = word.replace(u'[·ker·/k·er.]', u'ker')
word = word.replace(u'[·ſt/ſt·]', u'ſt')
# Verbliebene komplexe Trennstellen::
# if ('[' in word) or ('{' in word):
# print word.encode('utf8')
# Einfache Trennzeichen::
table = {ord(u'·'): None,
ord('='): None,
ord('-'): None,
ord('_'): None,
ord('.'): None,
}
return word.translate(table)
# Kategorien
# ==========
#
# Der Algorithmus sortiert die Wörter der Trennliste in die folgenden
# Kategorien:
#
#
# Menge aller Wörter der Liste (ohne Trennmuster)::
words = set()
# Automatisch konvertierte Wörter (ohne Trennmuster)::
completed = []
# Offene Fälle mit Trennmuster-Feldern wie im Original:
#
# Zur automatischen Konvertierung fehlt die Unterscheidung in Haupt- und
# Nebentrennstellen (Wichtung)::
ungewichtet = []
# Der Algorithmus kann die Schreibweise (noch) nicht ermitteln
# (mit teilweisen Ersetzungen)::
offen = []
# (Noch) nicht behandelt::
reformschreibung = [] # Schreibweisen nach neuer Rechtschreibung
sz_ersetzung = [] # Schreibweisen mit ß-Ersetzungen
# Die originale Wortliste ist mit 'latin-1' kodiert aber lokal nach
# utf8 konvertiert. Versuche zunächst ::
source_encoding = 'utf8'
# und stelle bei Fehlern auf 'latin-1' um.
# Hauptschleife
# =============
#
# Iteration über alle Zeilen der Wortliste::
for line in wordfile:
# Dekodieren und Entfernen der Zeilenendezeichen
# ----------------------------------------------
try:
line = line.rstrip().decode(source_encoding)
except UnicodeError:
source_encoding = 'latin1'
line = line.rstrip().decode(source_encoding)
# Kommentare ignorieren (werden mit # eingeleitet)::
line = line.split(u'#')[0]
# Zerlegen in Felder
# ------------------
#
# 1. Wort ungetrennt
# 2. Wort mit Trennungen, falls für alle Varianten identisch,
# anderenfalls leer
# 3. falls Feld 2 leer, Trennung nach traditioneller Rechtschreibung
# 4. falls Feld 2 leer, Trennung nach reformierter Rechtschreibung (2006)
# 5. falls Feld 2 leer, Trennung für Wortform, die entweder in
# der Schweiz oder mit Großbuchstaben oder Kapitälchen benutzt wird
# und für traditionelle und reformierte Rechtschreibung identisch ist
# 6. falls Feld 5 leer, Trennung für Wortform, die entweder in
# der Schweiz oder mit Großbuchstaben oder Kapitälchen benutzt wird,
# traditionelle Rechtschreibung
# 7. falls Feld 5 leer, Trennung für Wortform, die entweder in
# der Schweiz oder mit Großbuchstaben oder Kapitälchen benutzt wird,
# reformierte Rechtschreibung (2006)
# 8. falls Feld 5 leer, Trennung nach (deutsch)schweizerischer
# Rechtschreibung; insbesondere Wörter mit "sss" gefolgt von
# einem Vokal, die wie andere Dreifachkonsonanten gehandhabt wurden
# (also anders, als der Duden früher vorgeschrieben hat), z.B.
# "süssauer"
#
# ::
fields = line.split(';')
# Auswahl der Schreibweise
# ------------------------
#
# Zur Zeit werden nur Wörter in traditioneller Schreibweise behandelt::
i = 1 # 2. Feld: allgemeingültige Trennung
if fields[i] == '-2-': # keine allgemeingültige Trennung
i = 2 # 2. Feld: traditionelle Trennung
if fields[i] == '-3-': # Wort existiert nicht in traditioneller Schreibung
if fields[3] == '-4-': # Wort existiert nicht in Reformschreibung
sz_ersetzung.append(fields)
else:
reformschreibung.append(fields)
continue
word = fields[i] # Wort mit Trennstellen
# Menge aller Wörter der gewählten Schreibweise (ohne Trennstellen)::
words.add(fields[0])
# Vorsortieren
# ------------
#
# Wörter ohne Binnen-s müssen nicht konvertiert werden. Damit wird die
# Wortliste ungefähr um die Hälfte kürzer::
if 's' not in fields[0][:-1]:
completed.append(fields[0])
continue
# # nur vorsortieren:
# offen.append(fields)
# continue
# Regelbasierte s-ſ-Schreibung::
word = s_ersetzen(word)
# Einsortieren nach Vollständigkeit der Ersetzungen::
if is_complete(word):
completed.append(join_word(word))
continue
fields[i] = word # Rückschreiben von teilweisen Ersetzungen
if word.find(u's·ſ') != -1 or word.find(u's·z') != -1:
ungewichtet.append(fields)
continue
offen.append(fields)
# --------------------------------------------------------------------------
#
# Ende der Hauptschleife
#
# Feedback
# ========
#
# ::
print "Gesamtwortzahl (traditionelle Rechtschreibung)", len(words)
print "Automatisch konvertiert", len(completed)
print "nur in neuer Rechtschreibung", len(reformschreibung)
print "Schweizer und Großschreibvarianten", len(sz_ersetzung)
print "Wichtung der Trennstellen fehlt", len(ungewichtet)
print "noch offen", len(offen)
print "\nkonvertiert+offen", len(completed) + len(ungewichtet) + len(offen)
# Diskussion
# ==========
#
# Statistik
# ---------
#
#
# | Gesamtwortzahl (traditionelle Rechtschreibung) 417629
# | Automatisch konvertiert 411341
# | nur in neuer Rechtschreibung 4653
# | Schweizer und Großschreibvarianten 8745
# | Wichtung der Trennstellen fehlt 6280
# | noch offen 8
#
#
# Die große Mehrzahl der Wörter der Trennliste wurde nach den Regeln des
# Dudens in die Schreibung mit langem s (ſ) konvertiert.
#
# Der größte Teil der noch offenen Fälle kann durch Wichtung der
# Trennstellen (z.B. mit dem SiSiSi_-Algorithmus) gelöst werden.
#
# Für eine beschränke Anzahl offener Fälle wurden Ausnahmeregeln und Ausnahmen
# implementiert.
#
# Das Resultat muß noch auf nicht erfaßte Ausnahmen und Sonderfälle geprüft
# werden.
#
# Auch wenn der Algorithmus eher konservativ ist, sind Fehlentscheidungen
# insbesondere in Spezialfällen und Fremdwörtern nicht auszuschließen.
#
# Problemfälle
# ------------
#
# Wörter mit ſ am Wort oder Silbenende:
#
# * Tonarten/Töne: Aſ, Deſ, ...
#
# * sz (und st, sp in Reformschreibung): aber rundes s am Wortende
#
# Wie ist mit Trennungen nach übliche Vorsilben (aus-, bis-, ...) zu
# verfahren: Haupt- oder Nebentrennstelle?
# Ggf. neues Symbol: Nebentrennstelle, die aber Schluss-s verlangt?
#
# Wörter mit identischer Schreibung ohne lang-s:
#
# * Wach[s/ſ]tube, As/Aſ, ...?
#
# Probleme der Worliste:
#
# * Abkürzungen (Ausg, hrsg, insb msec, nsec)
#
# Ausgabe
# =======
#
# Wortliste mit automatisch bestimmter S-Schreibung, ohne Trennstellen::
completed.append(u'') # für das letzte Zeilenendezeichen
completed_file = file('wortliste-lang-s', 'w')
completed_file.write(u'\n'.join(completed).encode('utf8'))
# Wortlisten mit noch offenen Fällen::
for todo in ['ungewichtet', 'offen']:
todo_file = file('wortliste-lang-s-'+todo, 'w')
todo = globals()[todo] # get variable from string
todo = [u';'.join(fields) for fields in todo]
todo.append(u'') # für das letzte Zeilenendezeichen
todo_file.write(u'\n'.join(todo).encode('utf8'))
# Quellen
# =======
#
#
#
# .. [Duden] `Der Große Duden` 16. Auflage, VEB Bibliographisches Institut
# Leipzig, 1971
#
# Kennzeichnet im Stichwortteil rundes s durch Unterstreichen.
#
# .. [wikipedia]
# http://de.wikipedia.org/wiki/Langes_s
#
# .. _SiSiSi: https://www.ads.tuwien.ac.at/research/SiSiSi.html
#
# .. _Wortliste der deutschsprachigen Trennmustermannschaft:
# http://mirrors.ctan.org/language/hyphenation/dehyph-exptl/projektbeschreibung.pdf
#
# .. Fragen, Spezialfälle, Beispiele
#
# http://www.e-welt.net/bfds_2003/bund/fragen/13_Langes%20oder%20rundes%20S.pdf
# http://www.e-welt.net/bfds_2003/bund/fragen/12_hs%20und%20scharfes%20s_1.pdf
Mehr Informationen über die Mailingliste Trennmuster