""" Automatische Bestimmung der S-Schreibung auf Basis der Silbentrennung in der `Wortliste der deutschsprachigen Trennmustermannschaft`. """
Contents
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)
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 |
Siehe [wikipedia] und ("DDR"-) [Duden] (Regeln K 44,45):
def s_ersetzen(word):
ſ steht im Silbenanlaut:
word = re.sub(ur'^s', ur'ſ', word) word = re.sub(ur'([·\-=.])s', ur'\1ſ', word)
ſ steht im Inlaut als stimmhaftes s zwischen Vokalen (gilt auch für ungetrenntes ss zwischen Selbstlauten, z.B. Hausse, Baisse):
word = re.sub(ur'([AEIOUYÄÖÜaeiouäöü])s([aeiouyäöü])', ur'\1ſ\2', word) word = re.sub(ur'([AEIOUYÄÖÜaeiouäöü])ss([aeiouyäöü])', ur'\1ſſ\2', word)
ſ steht in den Verbindungen sp, st, sch und in Digraphen:
word = word.replace(u'st', u'ſt') word = word.replace(u'sp', u'ſp') word = word.replace(u'sch', u'ſch') word = word.replace(u'ps', u'pſ') # ψ word = word.replace(u'Ps', u'Pſ') # Ψ
Die Verbindungen ss, sp, st und sz werden zu ſſ, ſp, ſt und ſz auch wenn sie durch eine Nebentrennstelle (Trennung innerhalb eines Wortbestandteiles) getrennt sind.
s bleibt rund vor einer Haupttrennstelle (Trennung an der Grenze zweier Wortbestandteile (Vorsilbe=Stamm, Bestimmungswort=Grundwort), im Auslaut und nach Vorsilben wie (r)aus-, dis-, konfis-, ple-bis- (zur Zeit mit Nebentrennstelle markiert):
# word = word.replace(u's-ſ', u'ſ-ſ') word = word.replace(u's.ſ', u'ſ.ſ') # word = word.replace(u's-p', u'ſ-p') word = word.replace(u's.p', u'ſ.p') # word = word.replace(u's-t', u'ſ-t') # Reformschreibung word = word.replace(u's.t', u'ſ.t') # für sz/ſz wurden Spezialregeln erstellt, die Vorkommnisse # in der Wortliste erfassen
TODO: Vorsilben mit Haupttrennstelle markieren oder Ausnahmeliste erstellen.
ſz trotz Trennzeichen:
word = re.sub(ur'es[-·]zen', ur'eſ-zen', word) # 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, ...
ſ 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)
Schreibung nach Regeln der Herkunftssprache. Dabei ist zu bedenken, daß zu der Zeit als das lange s im Antiquasatz noch üblich war (bis ca. 1800) die Rechtschreibung freier gehandhabt wurde und mehrfach Wandlungen unterworfen war [West06].
Im Deutschen werden im Fraktursatz nicht eingedeutschte Fremdwörter in Antiqua mit rund-s geschrieben.
The long, medial, or descending ess, as distinct from the short or terminal ess. In Roman script, the long ess was used everywhere except at the end of words, where the short ess was used, and frequently in what is now the digraph <ss>, which was often written <ſs> rather than <ſſ> [en.wiktionary.org]. See also [Typefounder08] and [West06].
word = word.replace(u'sh', u'ſh') # (englisch) word = word.replace(u'sc', u'ſc') # (englisch) 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) return word
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:
Einzelfä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). Dasselbe gilt für Doppel-s (aus Fremdwörtern) in der traditionellen Rechtschreibung:
word = re.sub(ur's(=|$)', ur'~\1', word) 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 st nicht getrennt):
# word = re.sub(ur'ss?([·.\-][^ptzſ])', ur'~\1', word) # konservativ word = re.sub(ur'ss?([·.\-][^pzſ])', ur'~\1', word) # traditionell
s steht nach den Vorsilben (r)aus-, dis-, konfis-, ple-bis-, (ergänzen):
word = re.sub(ur'(^|[·.\-=])[Rr]?[Aa]us([·.\-=])', ur'\1~\2', word) word = re.sub(ur'(^|[·.\-=])[Dd]is([·.\-=])', 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([knw])', ur'~\1', word)
und suche nach übrigen Vorkommen:
return 's' not in word
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)
Angabe der Sprachvariante nach [BCP47] (Reformschreibung 'de' oder 'de-1996', Schweiz 'de-CH', ...)
Zur Zeit werden nur Wörter in traditioneller Schreibweise behandelt:
rechtschreibung = 'de-1901'
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:
de_1996 = [] # Schreibweisen nach neuer Rechtschreibung de_CH = [] # 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.
Iteration über alle Zeilen der Wortliste:
for line in wordfile:
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]
Auswahlregeln:
Wort ungetrennt
Wort mit Trennungen, falls für alle Varianten identisch, anderenfalls leer
falls Feld 2 leer, Trennung nach traditioneller Rechtschreibung
falls Feld 2 leer, Trennung nach reformierter Rechtschreibung (2006)
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
falls Feld 5 leer, Trennung für Wortform, die entweder in der Schweiz oder mit Großbuchstaben oder Kapitälchen benutzt wird, traditionelle Rechtschreibung
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)
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"
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 de_CH.append(fields) else: de_1996.append(fields) continue word = fields[i] # Wort mit Trennstellen
Menge aller Wörter der gewählten Schreibweise (ohne Trennstellen):
words.add(fields[0])
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: ungewichtet.append(fields) continue offen.append(fields)
Wortliste mit automatisch bestimmter S-Schreibung, ohne Trennstellen:
completed_file = file('wortliste-lang-s', 'w') completed_file.write(u'\n'.join(completed).encode('utf8')) completed_file.write('\n')
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 = [fields[0] for fields in todo] todo_file.write(u'\n'.join(todo).encode('utf8')) todo_file.write('\n')
print "Gesamtwortzahl (traditionelle Rechtschreibung)", len(words) print "Automatisch konvertiert", len(completed) print "nur in neuer Rechtschreibung", len(de_1996) print "Schweizer und Großschreibvarianten", len(de_CH) print "Wichtung der Trennstellen fehlt", len(ungewichtet) print "noch offen", len(offen) print "\nkonvertiert+offen", len(completed) + len(ungewichtet) + len(offen)
Die Mehrzahl der Wörter der Trennliste wurde nach den Regeln des Dudens in die Schreibung mit langem S (ſ) konvertiert (wobei ungefähr die Hälfte der Wörter kein kleines s enthält womit die Konversion trivial wird).
Der größte Teil der ca. 16 000 noch offenen Fälle kann durch Unterscheidung in Haupt- und Nebentrennstellen (z.B. mit dem SiSiSi-Algorithmus) gelöst werden. CTAN enthält eine (alte) Variante mit Atomlisten im Text-Format (Ur-SiSiSi). Die im Rahmen einer Diplomarbeit [gruber03] entstandene Variante Java-SiSiSi enthält eine Schnittstelle zum Wortanalysealgorithmus, die es ermöglicht SiSiSi als Bibliothek in fremde Programme einzubinden.
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. Fehlentscheidungen sind nicht auszuschließen.
sp, ss, st und sz wird zu ſp, ſſ, ſt und ſz, auch wenn das ſ vor einer Nebentrennstelle steht (z.B. Weſ-pe, eſ-ſen, abbürſ-ten (Reformtrennung) und Faſ-zination)
Aber rundes s am Wortende und nach Vorsilben, z.B. dis=putieren, Aus=ſage, aus=tragen, aus=zeichnen.
Wie sollen Trennungen nach Vorsilben (schwache Hautptrennstellen) markiert werden?
| nach Vorsilben, + zwischen Teilwörtern, zum Beispiel: Ab|fall+ent|sor-gungs+ver-band
Wach[s/ſ]tube?
Tonarten (As-Dur oder Aſ-Dur)
Im Fraktur-Duden steht As in Antiqua mit rundem s, aber
im 1976-er [Duden] steht As ohne Unterstreichung des s.
Der Große Duden 16. Auflage, VEB Bibliographisches Institut Leipzig, 1971
Kennzeichnet im Stichwortteil rundes s durch Unterstreichen.
Andrew West, The rules for long s, 2006 http://babelstone.blogspot.com/2006/06/rules-for-long-s.html
A. Phillips und M. Davis, (Editoren.), Tags for Identifying Languages, http://www.rfc-editor.org/rfc/bcp/bcp47.txt
Martin Gruber, Effiziente Gestaltung der Wortanalyse in SiSiSi, Diplomarbeit, 2003, http://www.ads.tuwien.ac.at/publications/bib/pdf/gruber-03.pdf