using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Speech.Synthesis;
using System.Text.RegularExpressions;
namespace Mittelhochdeutsches_Hörbuch1
{
class Hedda
{
// Die Liste der von Hedda in Text vorgefundenen unbekannten Buchstaben:
public List<char> UnbekannteZeichen = new List<char>();
// Ein Lexion zur Aufnahme der abweichend auszusprechenden Wortformen:
private Dictionary<string, string> Lexikon = new Dictionary<string, string>
{
["rehtiu"] = "S1 R EH C . T Y lng",
["Genewîs"]="S2 G E lng . N EX . S1 V I lng S",
["tugenden"]="S1 T UH . G EX N . D EX N",
["manegen"]="S1 M AA . N EX . G EX N",
["maneger"]="S1 M AA . N EX . G EHX",
["mæzeclîchen"] = "S1 M EH lng . Z EX K . S2 L I lng . C EX N",
["künneschaft"] = "S1 K Y . N EX . S2 SH AA F T"
};
private Dictionary<string, string> LexikonDerPräfixe = new Dictionary<string, string>
{
["be"] = "B EX",
["ge"] = "G EX",
["ver"] = "F EHX",
["zer"] = "Z EHX",
["en"] = "EH N",
["unbe"] = "S1 UH N . B EX",
["unge"] = "S1 UH N . G EX",
["unver"] = "S1 UH N . F EHX",
["unzer"] = "S1 UH N . Z EHX"
};
Dictionary<string, string> LexionDerBuchstabenErsetzung = new Dictionary<string, string>
{
["î"] = "I lng",
["iu"] = "Y lng",
["ei"] = "E lng + IH",
["ie"] = "I lng + EH",
["a"] = "AA",
["â"]="AA lng",
["ä"]="A",
["ae"]="EH lng",
["æ"] ="EH lng",
["c"]="K",
["ch"]="X",
["e"]="EH",
["ê"]="E lng",
["i"]="IH",
["o"]="O",
["ô"]="O lng",
["oe"]="EU",
["œ"] ="EU",
["ö"]="OE",
["ou"]="AO + UH",
["öu"]="OI",
["ph"]="P + F",
["sc"]="SH",
["sch"]="SH",
["u"] = "UH",
["û"]="U lng",
["uo"]="U lng + O",
["ü"]="YH",
["üe"]="Y lng + EH",
["w"]="v",
["v"]="f",
["z"]="T + S",
["zz"]="Z",
// deutsche r-Laute:
["ür"]="UYX",
["or"]="OWX",
["ör"]="OE + AX",
["oer"]="EU lng + AX",
["œr"] = "EU lng + AX",
["er"]="EHX",
["ûr"]="UAX",
["aer"] = "EH lng + AX",
["ær"] = "EH lng + AX",
// Satzzeichen:
["."]="_.",
[","]="_,",
[":"]="_.",
[";"]="_,",
["?"]="_?",
["!"]="_!",
// ht,lh,rh
["ht"]="X T",
["hs"]="X T",
["lh"]="L C",
["rh"]= "R C"
// Weitere Ersetzungen folgen ...
};
// Kurzwörter, deren Betonung wechselt:
List<string> Kurzwörter = new List<string>
{ "vor","von","der","diu","die","daz","diz","ditz",
"den","dem","dan","und","in","im","ir",
"an","ze","al","ez","für","ich","er","si",
"wol","bî","hie","wi","wie","ein","niht",
"mîn","sîn","mich","sich","doch","noch","nâch",
"dar","zuo","ie","mit","mê", "ouch","nu","unz",
"als","vil","wan","gar"
};
/* Immer wieder gebrauchte reguläre Ausdrücke:
*/
Regex reAnfang; // findet Präfixe. Wird durch Programmcode im Konstruktor erzeugt.
Regex reSilbenkerne = new Regex(@"[aâeêiîoôöuûüáéíóúàèìòùæœ]{1,2}"); // Wird verwendet, um Silben zu zählen.
Regex reVersende =new Regex( @"ei|[bcdfghklmnprstvwz]e[rntlsz\.,;:\?!]{0,3}$"); //Wird verwendet, um Kadenz zu ermitteln (klingend/stumpf)
//Die folgenden reg. Ausdrücke finden Suffixe:
//1. Silben mit Murmellaut e [EH]=>[EX] 2. Mit Murmellaut [EXR]
Regex reEnde = new Regex(@"(?<Anfang>.+[^\.] )(?<Ei>E lng \+ IH )?(?<Links>(?(Ei)|(P \+ F |T \+ S |SH |[BCDFGHKLMNRSTVZ] )))EH (?<Rechts>N T |R T |L S |R S |[SZTRNK] )?(?<Satzzeichen>_[\.\,\?\!] )?$");
Regex reEndeER = new Regex(@"(?<Anfang>.+[^\.] )(?<Ei>E lng \+ IH )?(?<Links>(?(Ei)|(P \+ F |T \+ S |SH |[BCDFGHKLMNRSTVZ] )))EHX (?<Rechts>[NTS] )?$");
public void SchreibeLexikon()
{
Console.WriteLine("*** Lexikon ***");
foreach (KeyValuePair<string, string> paar in Lexikon.OrderBy(paar => paar.Key)) Console.WriteLine(paar.Key + "=> [" + paar.Value + "]");
}
private int Silbenzahl(string Text)
{
return reSilbenkerne.Matches(Text).Count;
}
private bool Klingend(string Zeile)
{
if (reVersende.Match(Zeile).Success)
{
// Wir akzeptieren das Resultat, wenn das letzte Wort von Zeile mehrsilbig ist:
if (Silbenzahl(Zeile.Split().Last()) > 1) return true;
}
return false; // Alle anderen Fälle.
}
public string FindeAussprache(string Wort)
{
string Aussprache = "S1 "; //Default
if (Kurzwörter.Contains(Wort)) Aussprache = ""; // Wenn das Wort nicht zu den meist unbetonten Kurzwörtern gehört!
/* Wir überprüfen, ob die Möglichkeit einer präfigierenden Vorsilbe besteht.
* Dazu muss das Wort mindestens vier Buchstaben und zwei Silben aufweisen:
*/
if (Wort.Length>4 && Silbenzahl(Wort) > 1)
{
Match Treffer = reAnfang.Match(Wort);
if (Treffer.Success) // Wenn es einen Treffer gibt ...
{
string Präfix = Treffer.Groups["Präfix"].ToString(); // ist dieser in Präfix gespeichert
// Erneute Überprüfung: Ist das gefundene Präfix zu lang?
if (Wort.Length-Präfix.Length > 2 && Silbenzahl(Wort.Substring(Präfix.Length))>0)
{
// Gut. Wir ersetzen.
Aussprache = LexikonDerPräfixe[Präfix] + " . S1 ";
Wort = Wort.Substring(Präfix.Length);
}
}
}
// Präfix oder nicht, jetzt wird die Aussprache des (Rest-)Wortes gefunden
// Dieser Teil von FindeAussprache hat sich nicht geändert.
int i = 0; // Index des Buchstabens, an dem wir uns gerade befinden.
while (i<Wort.Length) // Solange i < als die Wortlänge ist.
{
List<string> MöglicheBuchstabenFolgen;
MöglicheBuchstabenFolgen = LexionDerBuchstabenErsetzung.Keys // Die mhd. Buchstabenfolgen
.Where(Buchstaben => Buchstaben[0] == Wort[i]) // bei denen der erste Buchstabe und der aktuelle unseres Suchbegriffes identisch sind.
.ToList(); // als Liste.
MöglicheBuchstabenFolgen.Sort((Folge1,Folge2)=>Folge2.Length.CompareTo(Folge1.Length)); // Sortiere die Liste absteigend nach ihrer Länge.
/* Wir gehen die Buchstabenfolgen mit dem gesuchten Anfang,
* die der Länge nach, absteigend sortiert sind,
* eine nach der anderen durch und überprüfen,
* ob sie sich ganz an der Stelle i in unserem Wort finden.
* Wenn die erste (längste) Folge identifiziert wird,
* brechen wir die Suche ab und ersetzen.
* Andernfalls suchen wir weiter.*/
bool Gefunden = false; //
foreach (string Buchstabenfolge in MöglicheBuchstabenFolgen)
{
if (Wort.Length-i >= Buchstabenfolge.Length && Wort.Substring(i, Buchstabenfolge.Length) == Buchstabenfolge)
{
string Ersatz = LexionDerBuchstabenErsetzung[Buchstabenfolge];
if (Ersatz[0]=='X')
{
if (i - 1 >= 0 && "iîeêöüäœæ".Contains(Wort[i - 1])) Ersatz = "C";
if (i - 2 >= 0 && Wort.Substring(i-2,2)=="iu") Ersatz = "C";
}
if (Ersatz=="T + S")
{
if (i - 1 >= 0 && "aouâôûiîeêöüäœæ".Contains(Wort[i - 1])) Ersatz = "Z";
}
Aussprache += Ersatz; // X += Y ist X = X + Y
Aussprache += ' '; //nicht das Leerzeichen vergessen!
i += Buchstabenfolge.Length;
Gefunden = true;
break; // Ein Ersatz gefunden, wir suchen nicht mehr weiter!
}
}
if (!Gefunden)
{
// Unbekannter Buchstabe
// Falls noch nicht in der Liste der unbekannten Zeichen,
// trage ihn ein.
if (!UnbekannteZeichen.Contains(Wort[i])) UnbekannteZeichen.Add(Wort[i]);
i += 1; // Zähle Weiter
}
}
// Jetzt kümmern wir uns um das Ende des Wortes:
if (Silbenzahl(Wort) > 1)
{
/* Wir fragen ab, ob eine unbetonte Endsilbe existieren kann und speichern das Ergebnis
Der ziemlich komplizierten Abfrage speichert reEnde in vier Variablen:
Anfang - speichert den Beginn des Wortes VOR der Endsilbe
Links - speichert den linken Rand der Silbe.
Rechts - entsprechend den rechten Rand.
Satzzeichen - nimmt ein etwaiges Satzzeichen auf.
*/
Match Suffix = reEnde.Match(Aussprache);
if (Suffix.Success)
{
// Wenn unsere Suche Erfolg hatte, setzen wir das Ergebnis zusammen:
Aussprache = Suffix.Groups["Anfang"]+"" + Suffix.Groups["Ei"] + ". "+Suffix.Groups["Links"] + " EX " + Suffix.Groups["Rechts"]+Suffix.Groups["Satzzeichen"];
}
// Wir kümmern uns jetzt auch um Wörter auf -er, bei denen das Ende EHX ist:
Suffix = reEndeER.Match(Aussprache);
if (Suffix.Success)
{
// Wenn unsere Suche Erfolg hatte, setzen wir das Ergebnis zusammen:
Aussprache = Suffix.Groups["Anfang"] +""+ Suffix.Groups["Ei"]+ ". " + Suffix.Groups["Links"] + "EHX " + Suffix.Groups["Rechts"] + Suffix.Groups["Satzzeichen"];
}
}
return Aussprache;
}
public void LeseZeile (string Zeile, PromptBuilder pb)
{
/* Los geht's Hedda!
* Lies Wort für Wort.
* Überprüfe, ob das Wort im Lexikon vermerkt wurde.
* Wenn ja, dann folge der dort in Lautschrift notierten Aussprache.
* Wenn nicht ... mach's wie immer, sprich so, wie es da "geschrieben" steht.*/
int SilbenImVers = Silbenzahl(Zeile);
int Silbe = 0;
foreach (string w in Zeile.ToLower().Split(' '))
{
string Satzzeichen = ".,?!;:".Contains(w.Last()) ? w.Last().ToString():null;
string Wort = Satzzeichen==null ? w:w.Substring(0, w.Length - 1);
Silbe += Silbenzahl(Wort);
if (Lexikon.Keys.Contains(Wort))
{
string Sonderbetonung = "";
if (Kurzwörter.Contains(Wort))
{
if ((SilbenImVers-Silbe) % 2 == 1 && Klingend(Zeile)) Sonderbetonung = "S1 " ;
if ((SilbenImVers-Silbe) % 2 == 0 && !Klingend(Zeile)) Sonderbetonung = "S1 ";
}
//Sonderfall, der im Lexikon gefunden wurde:
pb.AppendSsmlMarkup(@"<phoneme alphabet=""ups"" ph="""
+Sonderbetonung
+ Lexikon[Wort] + @""">"// Die Lautschriftvariante
+ Wort + "</phoneme>");// gefolgt von der Graphie
}
else
{
// Unbekanntes Wort, ermittel den Ausspracheregeln folgend die korrekte Lautung:
string Lautung = FindeAussprache(Wort);
if (Lautung != "")
{
Lexikon[Wort] = Lautung;
if (Kurzwörter.Contains(Wort))
{
if ((SilbenImVers-Silbe) % 2 == 1 && Klingend(Zeile)) Lautung = "S1 " + Lautung;
if ((SilbenImVers-Silbe) % 2 == 0 && !Klingend(Zeile)) Lautung = "S1 " + Lautung;
}
pb.AppendSsmlMarkup(@"<phoneme alphabet=""ups"" ph="""
+ Lautung + @""">"// Die Lautschriftvariante
+ Wort + "</phoneme>");// gefolgt von der Graphie
}
}
if (Satzzeichen != null)
{
pb.AppendSsmlMarkup(@"<phoneme alphabet=""ups"" ph="""
+ LexionDerBuchstabenErsetzung[Satzzeichen] + @""">"// Die Lautschriftvariante
+ Satzzeichen + "</phoneme>");// gefolgt von der Graphie
if (".?!".Contains(Satzzeichen))
{
/* pb.EndSentence();
pb.AppendBreak(PromptBreak.ExtraSmall);
pb.StartSentence();*/
}
}
}
pb.AppendBreak(Klingend(Zeile)?PromptBreak.ExtraSmall:PromptBreak.Small);
}
public Hedda()
{
string EinfachBuchstaben = "bdfghjklmnprst";
foreach( char c in EinfachBuchstaben)
{
LexionDerBuchstabenErsetzung[c.ToString()] = c.ToString().ToUpper();
}
// Wir bauen die Suchanfrage für die Präfixe auf:
List<string> Präfixe = LexikonDerPräfixe.Keys.ToList();
Präfixe.Sort((Präfix1, Präfix2) => Präfix2.Length.CompareTo(Präfix1.Length));
string Suche = @"^(?<Präfix>" + String.Join("|", Präfixe) + ")";
// Wir suchen. "Treffer" enthält die Suchergebnisse
Regex reAnfang = new Regex(Suche);
}
}
}