Major System

Code-Stücke können hier veröffentlicht werden.
Antworten
yoda
User
Beiträge: 14
Registriert: Montag 23. Juli 2018, 11:49

Ich habe mal ein kleines Tool erstellt, um eingegebene Wörter in das Major-System (https://de.wikipedia.org/wiki/Major-System) zu überführen. Feedback wäre toll :) Und vielleicht hat noch jemand eine Idee, wie man z.B. "g (weich)" und "g (hart)" unterscheiden könnte.

Code: Alles auswählen

try:
    import tkinter as tk
except ImportError:
    import Tkinter as tk

import itertools

IGNORIER_ZEICHEN = ["a", "e", "i", "o", "u", "h", "y"]
CODE = {
	"t" : "1", 
	"d" : "1", 
	"n" : "2", 
	"m" : "3",
	"r" : "4",
	"l" : "5",
	"j": "6",
	"k" : "7",
	"f" : "8",
	"v" : "8",
	"w": "8",
	"b" : "9",
	"p" : "9", 
	"s" : "6",
	"z" : "0",
	"ß" : "0", 
	"q" : "7"
}
KOMBIS = {"th": "t", "sch": "j", "ch":"j", "ck": "k", "ph": "f"}


class App(tk.Tk):
	def __init__(self):
		tk.Tk.__init__(self)
		self.eingabe = tk.Entry(self)
		self.button = tk.Button(
			self, text="codieren", command=self.major_kodieren
		)
		self.label = tk.Label(self)
		self.eingabe.pack()
		self.button.pack()
		self.label.pack()

	def major_kodieren(self):
		""" Uebersetze das eingegeben Wort in das Major System """
		wort = self.parse(self.eingabe.get())
		codierung = ""
		for zeichen in wort: 
			if zeichen not in IGNORIER_ZEICHEN:
				codierung += CODE[zeichen]
		self.label.config(text=codierung)

	def parse(self, wort):
		""" Macht ein Wort bereit fuer die Kodierung
		- entferne doppelte Buchstaben
		- mache das Wort lowercase
		- ersetze Buchstabenkombis durch einen Buchstaben, der
		  dem richtigen Laut entspricht
		"""
		wort = (''.join(ch for ch, _ in itertools.groupby(wort))).lower()
		
		for kombi in KOMBIS.keys():
			wort = wort.replace(kombi, KOMBIS[kombi])
		return wort


def main():
	app = App()
	app.mainloop()


if __name__ == '__main__':
	main()

Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@yoda: Okay, Feedback (Du hast gefragt… :-þ):

`IGNORIER_ZEICHEN` könnte ein `set()` sein. Bei `KOMBIS` wird das Wörterbuch überhaupt nicht benutzt, das könnte eine Liste mit Paaren sein. Auf jeden Fall sollte man über die Paare (items()-Methode) iterieren statt über die Schlüssel um die dann in der Schleife nur für den Zugriff auf den Wert zu verwenden.

In `major_kodieren()` ist ein „anti pattern“: das ``+=`` mit Zeichenketten in einer Schleife. In `parse()` ist es ja schon idiomatisch mit `join()` gelöst.

Wozu ist `IGNORIER_ZEICHEN` eigentlich gut? Was ist mit Zeichen die weder dort noch in `CODE` vorkommen? Willst Du nicht eigentlich alles ignorieren was nicht in `CODE` als Schlüssel steht?

Kennst Du die `translate()`-Methode auf Zeichenketten?

Es macht ja einen Unterschied ob man erst die doppelten Zeichen entfernt und dann in Kleinbuchstaben umwandelt oder umgekehrt. Ist das wiklich in der richtigen Reigenfolge?

Mir ist die Aufteilung der beiden Methoden nicht so ganz klar. Unter `parse()` hätte ich auch etwas anderes verstanden. Zudem sind das eigentlich keine GUI-Funktionen sondern Programmlogik die man auch ohne GUI oder mit einer anderen GUI nutzen könnte, wenn's nicht in einer GUI-Klasse stecken würde.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Das ganze Vorgehen ist nicht so optimal. Du mußt als erstes die Wörter in Laute umwandeln, denn es gibt noch so einige andere Doppelbuchstaben, die Du noch nicht in Deiner Kombi-Liste hast, "Stadt" und andere, wo doppelte Buchstaben zweifach gezählt werden, "Stadttor".
yoda
User
Beiträge: 14
Registriert: Montag 23. Juli 2018, 11:49

@BlackJack: Vielen Dank für deine Kritik, werde ich versuchen umzusetzen.
@Sirius3: Ja, da hast du Recht. Meine Idee wäre, die Eingabe zuerst in IPA umzuwandeln. Aber ich weiß nicht, wie ich das am sinnvollsten mache. Über's Internet? Dann kann ich ja gleich eine Internetseite mit Major-Konverter aufrufen :D Über zusätzliche Packages? Auch nicht toll, da es vom Nutzer zusätzlich installiert werden müsste.
yoda
User
Beiträge: 14
Registriert: Montag 23. Juli 2018, 11:49

Ich habe mich jetzt nochmal rangesetzt und versucht die Tipps umzusetzen :)
@BlackJack
`IGNORIER_ZEICHEN` könnte ein `set()` sein. Bei `KOMBIS` wird das Wörterbuch überhaupt nicht benutzt, das könnte eine Liste mit Paaren sein. Auf jeden Fall sollte man über die Paare (items()-Methode) iterieren statt über die Schlüssel um die dann in der Schleife nur für den Zugriff auf den Wert zu verwenden.
Das verstehe ich nicht wirklich. Ich brauche ja KOMBIS, um Buchstabenkombinationen durch Buchstaben zu ersetzen, die den entsprechenden Laut haben. Auch verstehe ich nicht, warum man nicht einfach über die Schlüssel iterieren kann. Wo liegt der Unterschied?
Kennst Du die `translate()`-Methode auf Zeichenketten?
Kannte ich noch nicht, danke für den Tipp. Kann man die hier sinnvoll einsetzen? Dann müsste man ja CODE wieder um die Zeichen erweitern, die man ignorieren will ('a': None, 'i': None, ...).
Mir ist die Aufteilung der beiden Methoden nicht so ganz klar. Unter `parse()` hätte ich auch etwas anderes verstanden. Zudem sind das eigentlich keine GUI-Funktionen sondern Programmlogik die man auch ohne GUI oder mit einer anderen GUI nutzen könnte, wenn's nicht in einer GUI-Klasse stecken würde.
Ich habe jetzt versucht, GUI und Programmlogik zu trennen. Gibt es da eine elegantere Lösung als meine label_updaten Methode?

@Sirius3: Für das Umwandeln von Text in IPA habe ich immer noch keine Idee, die nicht zu aufwendig ist.

Hier der Code

Code: Alles auswählen

try:
    import tkinter as tk
except ImportError:
    import Tkinter as tk

import itertools

CODE = {
	"t" : "1", 
	"d" : "1", 
	"n" : "2", 
	"m" : "3",
	"r" : "4",
	"l" : "5",
	"j" : "6",
	"k" : "7",
	"f" : "8",
	"v" : "8",
	"w" : "8",
	"b" : "9",
	"p" : "9", 
	"s" : "6",
	"z" : "0",
	"ß" : "0", 
	"q" : "7"
}

KOMBIS = {
	"th": "t", 
	"sch": "j", 
	"ch":"j", 
	"ck": "k", 
	"ph": "f", 
	"dt": "t", 
	"st":"j"
}


class App(tk.Tk):
	def __init__(self):
		tk.Tk.__init__(self)
		self.eingabe = tk.Entry(self)
		self.button = tk.Button(
			self, text="codieren", command=self.label_updaten
		)
		self.label = tk.Label(self)
		self.eingabe.pack()
		self.button.pack()
		self.label.pack()

	def label_updaten(self):
		self.label.config(
			text=major_kodieren(self.eingabe.get())
		)


def major_kodieren(wort):
	wort = (''.join(ch for ch, _ in itertools.groupby(wort.lower())))
	for paar in KOMBIS.items():
		wort = wort.replace(paar[0], KOMBIS[paar[0]])
	return ''.join(CODE[ch] for ch in wort if ch in CODE.keys())


def main():
	app = App()
	app.mainloop()


if __name__ == '__main__':
	main()

Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@yoda: Du iterierst bei `KOMBIS` über Schlüssel, um in der Schleife dann auf den Wert zuzugreifen, und benötigst dort immer beide zusammen. Dafür benutzt Du nicht die Eigenschaft das man bei Wörterbüchern schnell über einen Schlüssel auf den Wert zugreifen kann, weil das keinen Vorteil bringt wenn man über *alle* Schlüssel-Wert-Paare iteriert.

Du hast:

Code: Alles auswählen

for old in dictionary:
    do_something(old, dictionary[old])
Das wäre lesbarer geschrieben als:

Code: Alles auswählen

for old, new in dictionary.items():
    do_something(old, new)
Dafür braucht man aber kein Wörterbuch, da reicht eine Sequenz von Paaren:

Code: Alles auswählen

pairs = [('alt', 'neu'), ('noch was altes', 'noch was neues')]
for old, new in pairs:
    do_something(old, new)
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
yoda
User
Beiträge: 14
Registriert: Montag 23. Juli 2018, 11:49

@BlackJack. Jetzt verstehe ich was du meinst. Aber warum ist eine Liste von Paaren besser als ein Dictionary? Und kann man das mit der 'label_updaten()'-Funktion noch verbessern?

Hier nochmal die neue Stelle

Code: Alles auswählen

...

KOMBIS = [
	("th", "t"),
	("sch", "j"), 
	("ch","j"), 
	("ck", "k"), 
	("ph", "f"), 
	("dt", "t"), 
	("st","j")
]
...
def major_kodieren(wort):
  wort = (''.join(ch for ch, _ in itertools.groupby(wort.lower())))
  for kombi, laut in KOMBIS:
    wort = wort.replace(kombi, laut)
  return ''.join(CODE[ch] for ch in wort if ch in CODE.keys())
  ...
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Mal das ganze mit regulären Ausdrücken:

Code: Alles auswählen

import re

CODE = {
    "t" : "1", 
    "d" : "1", 
    "n" : "2", 
    "m" : "3",
    "r" : "4",
    "l" : "5",
    "j" : "6",
    "s" : "6",
    "sch": "6",
    "ch": "6",
    "st": "6",
    "k" : "7",
    "q" : "7",
    "f" : "8",
    "ph": "8",
    "v" : "8",
    "w" : "8",
    "b" : "9",
    "p" : "9", 
    "z" : "0",
    "ß" : "0",
}

CODE_RE = re.compile("|".join(sorted(CODE, key=len, reverse=True)), re.I)

def major_kodieren(wort):
    encoded = CODE_RE.sub(lambda g: CODE[g.group(0).lower()], wort)
    return re.sub(r'\D*(\d?)\1*',r'\1', encoded) # remove duplicates
nezzcarth
User
Beiträge: 1632
Registriert: Samstag 16. April 2011, 12:47

yoda hat geschrieben: Montag 20. August 2018, 18:52 @Sirius3: Für das Umwandeln von Text in IPA habe ich immer noch keine Idee, die nicht zu aufwendig ist.
Ein Stichwort wäre hier Grapheme-Phomene-Conversion (G2P) auch wenn das streng genommen nicht ganz dasselbe ist. Wenn du nicht vor hast, dich da tiefer einzugraben, würde ich von dem Vorhaben absehen, da das nicht trivial ist. Falls du dich da nicht einarbeiten möchtest, kannst du dir mal die verschiedenen freien Text-To-Speech Systeme ansehen; die brauchen solche Komponenten natürlich auch und einige davon haben zumindest ein Commandline Interface dafür.

Auch wenn direktes IPA dank Unicode zwar ginge, nimmt man meist dann doch eher Systeme wie (x)-sampa zur Repräsentation (https://de.wikipedia.org/wiki/X-SAMPA). IPA stellt aber natürlich nur die optische Repräsentation dar; intern lassen sich Laute z.B. als Merkmals-Matrizen abbilden.
Antworten