Subtrees hinzugefügt

This commit is contained in:
Dirk Zechnall 2025-01-05 23:45:15 +01:00
parent 0a64a479b0
commit 29d4112506
42 changed files with 2889 additions and 0 deletions

View file

@ -0,0 +1,7 @@
**/*.sh
**/*.class
**/*.ctxt
repo.adoc
repo_subtree.adoc
/alt
/hide

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path=""/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER">
<attributes>
<attribute name="module" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/5"/>
<classpathentry kind="output" path="bin"/>
</classpath>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>tabellen-dfa</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View file

@ -0,0 +1,127 @@
/**
* Implementiert einen DEA, der 0/1-Folgen darauf prüft, ob
* sie "gültige Binärzahlen" darstellen.
* Gültige Binärzahlen im Sinne dieser Aufgabe beginnen mit
* einer 1, auf die eine beliebige Folge von 0/1 folgt. Die
* einzelne Ziffer 0 ist ebenfalls erlaubt, jedoch keine
* Binärzahlen mit "überflüssigen" führenden Nullen. Die
* Binärzahl darf außerdem ein Vorzeichen führen (muss aber
* nicht).
*
* Gültig sind beispielsweise:
* 1
* 0
* 101
* 11
* 10
* 1110010010
* 111
* -1
* 1000000000
* +1
* 1001001100
*
* Ungültig sind beispielsweise:
* 123
* 00
* hallo
* 0000000011111
* 1+1
* Binärzahl
* abc
* 321
* 01010101010101
* 0101
* 01
* 0101010101
*
* @author Urs Lautebach
* @version 2021-Januar
*/
/* Lehrertipps:
* 1.
* Diese Beispielaufgabe kann bei Bedarf noch vereinfacht
* werden, indem zunächst die Vorzeichen weggelassen werden.
* Allerdings passen dann die mitgelieferten Unit-Tests nicht!
*
* 2.
* Viele Schüler muss man daran erinnern, beim Testen gezielt
* auch ungültige Wörter zu verwenden.
*
* 3.
* Die Lösung setzt etwas Erfahrung mit mehrdimensionalen
* Arrays voraus.
*/
public class BinaerzahlenPruefer extends EndlicherAutomat {
/* Bei der Implementierung dieser Klasse muss man nur
* die Attribute alphabet, uebergaenge und endzustaende
* geeignet festlegen -- alles andere macht die
* Vaterklasse "EndlicherAutomat.java".
*
* Dort ist auch erklärt, wie die Nummerierung der
* Zustände, des Startzustand und der Übergangstabelle
* zu verstehen sind.
*/
// Transitionstabelle anlegen mit den Zuständen auf der
// senkrechten und den Alphabetzeichen auf der Rechtsachse:
private static final int[][] transiTabelle = new int [][] {
/* die erste Zeile enthaelt die Sprünge heraus aus
* dem Fehlerzustand 0 (den der Automat ja aber gar
* nicht wieder verlassen darf), die also alle 0 sind:
*/
{ 0,0,0,0 },
{ 2,2,3,4 },
{ 0,0,3,4 },
{ 0,0,0,0 },
{ 0,0,4,4 },
};
// Alphabet für diesen Automaten als char[]
private static final char[] binaerzAlph = new char[] {
'-', '+', '0', '1'
};
// Menge der Endzustände:
private static final int[] endzustaende = new int[] {
3, 4
};
/**
* Konstruktor für einen BinaerzahlenPruefer:
*/
public BinaerzahlenPruefer() {
// Aufruf des super-Konstruktors:
super(binaerzAlph, transiTabelle, endzustaende);
}
/**
* Die main-Methode erlaubt den Aufruf von
* Binaerzahlenpruefer von der Kommandozeile aus mit
* mehreren zu testenden Strings:
*
* java BinaerzahlenPruefer 1110101 0001 +1010 abc
*
* Die Ausgabe lautet dann
* Akzeptiert: "1110101" ist ein gueltiges Binärwort.
* FEHLER! "0001" ist kein gültiges Binärwort!
* Akzeptiert: "+1010" ist ein gueltiges Binärwort.
* FEHLER! "abc" ist kein gültiges Binärwort!
*/
public static void main(String[] args) {
// Endlichen Automaten instanziieren:
EndlicherAutomat binaerzahlenDFA = new BinaerzahlenPruefer();
for(String wort : args) {
if(binaerzahlenDFA.gehoertZuSprache(wort)) {
System.out.println("Akzeptiert: \"" + wort +
"\" ist ein gültiges Binärwort.");
} else {
System.out.println("FEHLER! \"" + wort +
"\" ist kein gültiges Binärwort!");
}
}
}
}

View file

@ -0,0 +1,104 @@
import static org.junit.Assert.*;
import org.junit.Test;
public class DEA_BeispieleTest {
public DEA_BeispieleTest() {
}
@Test
public void testBinaerzahlenPruefer() {
BinaerzahlenPruefer binZPruefer = new BinaerzahlenPruefer();
assertTrue(binZPruefer.gehoertZuSprache("1"));
assertTrue(binZPruefer.gehoertZuSprache("0"));
assertTrue(binZPruefer.gehoertZuSprache("+1"));
assertTrue(binZPruefer.gehoertZuSprache("+0"));
assertTrue(binZPruefer.gehoertZuSprache("-1"));
assertTrue(binZPruefer.gehoertZuSprache("-0"));
assertTrue(binZPruefer.gehoertZuSprache("11"));
assertTrue(binZPruefer.gehoertZuSprache("10"));
assertTrue(binZPruefer.gehoertZuSprache("+11"));
assertTrue(binZPruefer.gehoertZuSprache("-11"));
assertTrue(binZPruefer.gehoertZuSprache("+10"));
assertTrue(binZPruefer.gehoertZuSprache("1111"));
assertTrue(binZPruefer.gehoertZuSprache("1000"));
assertTrue(binZPruefer.gehoertZuSprache("10100101010111000"));
assertTrue(binZPruefer.gehoertZuSprache("1111111"));
assertFalse(binZPruefer.gehoertZuSprache(""));
assertFalse(binZPruefer.gehoertZuSprache("+"));
assertFalse(binZPruefer.gehoertZuSprache("-"));
assertFalse(binZPruefer.gehoertZuSprache("x"));
assertFalse(binZPruefer.gehoertZuSprache("binärzahl"));
assertFalse(binZPruefer.gehoertZuSprache("00"));
assertFalse(binZPruefer.gehoertZuSprache("+00"));
assertFalse(binZPruefer.gehoertZuSprache("0+0"));
assertFalse(binZPruefer.gehoertZuSprache("123"));
assertFalse(binZPruefer.gehoertZuSprache("0011"));
assertFalse(binZPruefer.gehoertZuSprache("011"));
assertFalse(binZPruefer.gehoertZuSprache("111111+"));
assertFalse(binZPruefer.gehoertZuSprache("000000+"));
assertFalse(binZPruefer.gehoertZuSprache("1+1"));
assertFalse(binZPruefer.gehoertZuSprache("0+1"));
assertFalse(binZPruefer.gehoertZuSprache("1+0"));
}
@Test
public void testMailadressenChecker() {
MailadressenChecker mailAdrPruefer = new MailadressenChecker();
assertTrue(mailAdrPruefer.gehoertZuSprache("b@b.bb"));
assertTrue(mailAdrPruefer.gehoertZuSprache("b@b.bbbb"));
assertTrue(mailAdrPruefer.gehoertZuSprache("b.b.b@bbb.bbb"));
assertTrue(mailAdrPruefer.gehoertZuSprache("bbbbbb@b.bb"));
assertTrue(mailAdrPruefer.gehoertZuSprache("b@b.b.b.b.bb"));
assertTrue(mailAdrPruefer.gehoertZuSprache("...@b.bb"));
assertTrue(mailAdrPruefer.gehoertZuSprache("...bbb@bb.bb"));
assertTrue(mailAdrPruefer.gehoertZuSprache("bbb...@bb.bb"));
assertFalse(mailAdrPruefer.gehoertZuSprache(""));
assertFalse(mailAdrPruefer.gehoertZuSprache("."));
assertFalse(mailAdrPruefer.gehoertZuSprache("b"));
assertFalse(mailAdrPruefer.gehoertZuSprache("@"));
assertFalse(mailAdrPruefer.gehoertZuSprache("bb@"));
assertFalse(mailAdrPruefer.gehoertZuSprache("b@b.b@bbb"));
assertFalse(mailAdrPruefer.gehoertZuSprache("@bb"));
assertFalse(mailAdrPruefer.gehoertZuSprache("bb@."));
assertFalse(mailAdrPruefer.gehoertZuSprache("bb@.."));
assertFalse(mailAdrPruefer.gehoertZuSprache("bb@bb.b"));
assertFalse(mailAdrPruefer.gehoertZuSprache("bb@bb.bb.b"));
assertFalse(mailAdrPruefer.gehoertZuSprache("bbb@bbb"));
assertFalse(mailAdrPruefer.gehoertZuSprache("bb.bb.bb.bb"));
assertFalse(mailAdrPruefer.gehoertZuSprache(
"bbb@bb.bb.bb@bb.bb"));
assertFalse(mailAdrPruefer.gehoertZuSprache("bbb@bbb..bbb"));
assertFalse(mailAdrPruefer.gehoertZuSprache("bbb@bbb.bbb.."));
}
@Test
public void test007Sucher() {
KGB_007Sucher detektiv = new KGB_007Sucher();
assertTrue(detektiv.gehoertZuSprache("007"));
assertTrue(detektiv.gehoertZuSprache("1007"));
assertTrue(detektiv.gehoertZuSprache("0071"));
assertTrue(detektiv.gehoertZuSprache("007007"));
assertTrue(detektiv.gehoertZuSprache("00007"));
assertTrue(detektiv.gehoertZuSprache("0000712"));
assertTrue(detektiv.gehoertZuSprache("2121200777"));
assertTrue(detektiv.gehoertZuSprache("0077"));
assertTrue(detektiv.gehoertZuSprache("212121007000000"));
assertTrue(detektiv.gehoertZuSprache("00712772712717"));
assertFalse(detektiv.gehoertZuSprache(""));
assertFalse(detektiv.gehoertZuSprache("0"));
assertFalse(detektiv.gehoertZuSprache("1"));
assertFalse(detektiv.gehoertZuSprache("2"));
assertFalse(detektiv.gehoertZuSprache("7"));
assertFalse(detektiv.gehoertZuSprache("07"));
assertFalse(detektiv.gehoertZuSprache("001"));
assertFalse(detektiv.gehoertZuSprache("002"));
assertFalse(detektiv.gehoertZuSprache("000"));
assertFalse(detektiv.gehoertZuSprache("001002"));
assertFalse(detektiv.gehoertZuSprache("7001"));
assertFalse(detektiv.gehoertZuSprache("0707"));
}
}

View file

@ -0,0 +1,212 @@
/**
* Implementiert einen tabellengetriebenen endlichen Automaten.
* Instanzen dieser Klasse sind DEAs, die Wörter über einem
* vorgegebenen Alphabet akzeptieren oder ablehnen können.
*
* Die Aufgabe wurde vom schriftlichen Abitur 2020 in
* Baden-Württemberg inspiriert.
*
* @author Urs Lautebach
* @version 2020-Oktober
*/
/* Lehrertipps:
*
* 1.
* Die Implementierung setzt etwas Erfahrung mit mehrdimensionalen
* Arrays sowie die Handhabung von String und char voraus.
*
* 2.
* Die Schüler sollten vor der Implementierung dieser Klasse
* schon Transitionstabellen von Hand erstellt (in der
* Regel aus einem Übergangsgraphen) und idealerweise auch
* schon "Läufe" der so beschriebenen DEAs von Hand simuliert
* haben. Wenn sie das sogar ohne den Übergangsgraphen tun,
* entsteht leichter die richtige Grundvorstellung davon, warum
* dieser "allgemeine" DEA beliebige konkrete DEAs simulieren
* kann.
*/
public class EndlicherAutomat {
private int [][] uebergaenge = null;
private int[] endzustaende = null;
private char[] alphabet = null;
/**
* Konstruiert einen tabellengetriebenen DEA. Nach dem
* erfolgreichen Aufruf dieses Konstruktors kann man den DEA
* anschließend durch einen Aufruf der Methode
* gehoertZuSprache(String):boolean
* beliebig viele Wörter testen lassen.
*
* @param tabelle Transitionstabelle des DEA. Die erste
* Dimension bezeichnet die Zustände; die zweite Dimension die
* Eingabezeichen. Die Einträge der Tabelle bezeichnen jeweils
* den Zustand, in den der Automat (abhängig vom vorherigen
* Zustand und der Eingabe) wechseln soll.
*
* Der Zustand 0 gilt als Fehlerzustand. Zustand 1 ist immer
* Startzustand (so dass der Startzustand, anders als bei der
* formalen Beschreibung eines DEA, nicht explizit angegeben
* werden muss).
*
* @param finalStates Ein int[], das die Endzustände enthält.
*
* @param alphabet ein Array von char, das das Alphabet des
* Automaten enthält. Die Reihenfolge der Zeichen im Alphabet
* muss der Reihenfolge der Zeichen an der entsprechenden
* Achse der Transitionstabelle entsprechen.
*/
EndlicherAutomat(final char[] alphabet,
final int[][] uebergaenge, final int[] endzustaende ) {
this.alphabet = alphabet;
this.uebergaenge = uebergaenge;
this.endzustaende = endzustaende;
// Die Methode plausibilitaetPruefen ist fertig vorgegeben;
// sie fängt einige offensichtliche Fehler ab:
plausibilitaetPruefen();
}
/**
* Die Methode prüft, ob die Attribute transitionstabelle,
* alphabet und endzustaende zueinander passen. Sie ist fertig
* implementiert und dafür gedacht, am Ende des Konstruktors
* aufgerufen zu werden.
*/
private void plausibilitaetPruefen() {
if (uebergaenge == null) {
throw new IllegalArgumentException(
"Die Übergangstabelle ist null oder leer!");
}
if (alphabet == null) {
throw new IllegalArgumentException(
"Das Alphabet ist null oder leer!");
}
if (endzustaende == null) {
throw new IllegalArgumentException(
"endzustaende ist null oder leer!");
}
int tabelleHoehe = this.uebergaenge.length;
int tabelleBreite = uebergaenge[0].length;
// Hat die Übergangstabelle eine Zeile pro Alphabetzeichen?
if (tabelleBreite != alphabet.length) {
throw new IllegalArgumentException("Das Alphabet hat " +
alphabet.length + " Zeichen, die " +
" Übergangstabelle aber " + tabelleBreite +
" Spalten!");
}
// Sind alle Zeilen der Transitionstabelle gleich lang?
for (int[] zeile : uebergaenge) {
if (zeile.length != tabelleBreite) {
throw new IllegalArgumentException(
"Übergangstabelle ist nicht rechteckig!");
}
}
// Hat einer der Endzustände eine unplausible Nummer?
for (int zustand : endzustaende) {
if (zustand < 1 || zustand > tabelleHoehe - 1) {
throw new IllegalArgumentException(
"Der Endzustand " + zustand +
" kommt in der Übergangstabelle nicht vor!");
}
}
}
/**
* Ermittelt die Nummer (den Index) des angegebenen Zeichens
* innerhalb des Alphabetes dieses Automaten.
*
* @param input Zeichen, dessen Position ermittelt werden soll.
* @returns Position des Zeichens input innerhalb des Alphabets
* dieses Automaten; oder -1, falls es im Alphabet nicht
* enthalten ist.
*/
public int indexImAlphabet(char input) {
/* Man geht das Alphabet durch und prüft, welches seiner
* Zeichen dem "input" entspricht. Falls man es findet,
* gibt man dessen Index zurück.
*/
for (int index = 0; index < alphabet.length; index++) {
if (input == alphabet[index])
return index;
}
return -1;
}
/**
* Überprüft, ob der Zustand mit der übergebenen
* Zustandsnummer einer der Endzustände dieses Automaten ist.
*
* @param nr Nummer des fraglichen Zustandes.
* @return ob der Zustand ein Endzustand ist.
*/
public boolean istEndzustand(int nr) {
for (int endzustand : endzustaende) {
// Gehe durch alle Endzustände. Wenn nr einer ist...
if (nr == endzustand) {
return true;
}
}
return false;
}
/**
* Die Methode kann mit einem String als Parameter aufgerufen
* werden, was oft bequemer ist als ein char[].
*
* @param s String mit dem zu prüfenden Wort.
* @return ob s von diesem Automaten erkannt wird.
*/
public boolean gehoertZuSprache(String s) {
// Hier ist nichts zu implementieren.
return gehoertZuSprache(s.toCharArray());
}
/**
* Übergibt dem DEA ein ganzes Wort und ermittelt, ob er es
* akzeptiert oder nicht.
*
* @param eingabe Die komplette zu analysierende Eingabe als
* char[].
* @returns true, wenn das Wort vom DEA akzeptiert wird;
* false sonst.
*/
public boolean gehoertZuSprache(final char[] wort) {
/*
* Um zu prüfen, ob wort akzeptiert wird, muss der DEA...
*
* - in Zustand 1 beginnen;
*
* - das Eingabewort Zeichen für Zeichen durchgehen;
*
* - prüfen, ob das Zeichen im Alphabet vorkommt;
*
* - nach dessen Position im Alphabet und altem Zustand
* einen neuen Zustand aus der Tabelle uebergaenge wählen;
*
* - false antworten, wenn er im Fehlerzustand landet,
*
* - am Schluss der Eingabe entscheiden, ob der erreichte
* Zustand ein Endzustand ist.
*/
// Startzustand ist immer Nr. 1:
int zustand = 1;
// Gehe durch alle Zeichen durch:
for (char zeichen : wort) {
int alphIndex = indexImAlphabet(zeichen);
// Falls das Zeichen gar nicht im Alphabet ist...:
if (alphIndex == -1) {
return false;
} else {
// wechsle in neuen Zustand:
zustand = uebergaenge[zustand][alphIndex];
}
// Bin ich im Fehlerzustand?
if (zustand == 0) {
return false;
}
}
// Die Eingabe ist verbraucht. Falls der aktuelle Zustand
// ein Endzustand ist, akzeptieren wir die Eingabe:
return istEndzustand(zustand);
}
}

View file

@ -0,0 +1,106 @@
/**
* Dieser DFA erkennt Ziffernfolgen, in denen sich irgendwo
* James Bond versteckt hat -- in denen also die Folge 007
* vorkommt.
*
* Die folgenden Ziffernfolgen sollen beispielsweise akzeptiert
* werden:
*
* 12107117700710012021,
* 007,
* 0071121727,
* 0000000071121727,
* 007007007007,
* 1121271201212007.
*
* Die folgenden Ziffernfolgen sollen nicht akzeptiert werden:
*
* 12107110710012021,
* 07,
* 00,
* 07112172,
* 1121271201212000.
* Um den Automaten und vor allem die Übergangstabelle
* übersichtlicher zu halten, verwendet er nicht alle Ziffern,
* sondern lediglich das eingeschränkte Alphabet {0, 1, 2, 7}.
*
* Es empfiehlt sich, den Automaten zunächst zu zeichnen,
* die Übergangstabelle auf Papier zu erstellen und dann zu
* programmieren.
*
* @author Urs Lautebach
* @version 2020-Okt
*/
/* Lehrertipps:
* 1.
* Viele Schüler muss man daran erinnern, beim Testen gezielt
* auch ungültige Wörter zu verwenden.
*
* 2.
* Die Lösung setzt etwas Erfahrung mit mehrdimensionalen
* Arrays voraus.
*
* 3.
* Die 007-Aufgabe ist ein Beispiel für das sogenannte
* "Substring-Problem", das im 2016er Informatik-Bildungsplan
* für Baden-Württemberg ausdrücklich erwähnt wird.
*/
public class KGB_007Sucher extends EndlicherAutomat {
/* Bei der Implementierung dieser Klasse muss man nur
* die Attribute alphabet, uebergaenge und endzustaende
* geeignet festlegen -- alles andere macht die
* Vaterklasse.
*/
private static final char[] alphabet = new char[] {
'0', '1', '2', '7'
};
private static final int[][] uebergaenge = new int[][] {
{ 0, 0, 0, 0 },
{ 2, 1, 1, 1 },
{ 3, 1, 1, 1 },
{ 3, 1, 1, 4 },
{ 4, 4, 4, 4 },
};
private static final int[] endzustaende = new int[] {
4
};
/**
* Instanziiert einen KGB_007Sucher-DFA.
*/
KGB_007Sucher() {
// Aufruf des super-Konstruktors:
super(alphabet, uebergaenge, endzustaende);
}
/**
* Die main-Methode erlaubt den Aufruf des
* Binaerzahlenpruefers von der Kommandozeile aus mit:
*
* java KGB_007Sucher 127007117 1717771021
*
* Die Ausgabe lautet dann
*
* Akzeptiert: "127007117" enthält 007.
* FEHLER! "1717771021" enthält kein 007!
*/
public static void main(String[] args) {
// Endlichen Automaten instanziieren:
EndlicherAutomat fahnder = new KGB_007Sucher();
for(String wort : args) {
if(fahnder.gehoertZuSprache(wort)) {
System.out.println("Akzeptiert: \"" + wort +
"\" enthält 007.");
} else {
System.out.println("FEHLER! \"" + wort +
"\" enthält kein 007!");
}
}
}
}

View file

@ -0,0 +1,114 @@
/**
* Die Klasse implementiert einen DEA für die Überprüfung äußerst
* einfacher Mailadressen, die nur aus dem Buchstaben b, Punkten
* und dem at-Zeichen bestehen dürfen. Der Nutzername darf fast
* beliebig aufgebaut sein; die Domain muss mindestens zweistufig
* sein und die Toplevel-Domain muss mindestens zwei Zeichen haben.
*
* Gültig sind damit beispielsweise:
* b@b.bb
* b@b.bbbb
* b.b.b@bbb.bbb
* bbbbbb@b.bb
* b@b.b.b.b.bb
* ...@b.bb
* ...bbb@bb.bb
* bbb...@bb.bb
*
* Ungültig sind beispielsweise:
* .
* b
* @
* bb@
* b@b.b@bbb
* b@b.b@bb.b
* @bb
* bb@.
* bb@..
*
* Tatsächlich ist die Überprüfung realer Mailadressen wesentlich
* komlizierter als in diesem Beispiel.
*
* @author Urs Lautebach
* @version 2021-Janar
*
*/
/* Lehrertipps:
* 1.
* Mit einem vollständigen Buchstabenalphabet wird die
* Transitionstabelle schnell unhandlich und besteht dann doch
* fast nur aus identischen Transitionen. Die Einschränkung
* auf einen einzigen Buchstaben erlaubt die Konzentration auf
* interessantere Fragen.
*
* 2.
* Diese Aufgabe kann bei Bedarf noch vereinfacht werden, indem
* einzelne Anforderungen weggelassen werden.
* Allerdings passen dann die mitgelieferten Unit-Tests nicht!
*
* 3.
* Viele Schüler muss man daran erinnern, beim Testen gezielt
* auch ungültige Wörter zu verwenden.
*
* 4.
* Die Lösung setzt etwas Erfahrung mit mehrdimensionalen
* Arrays voraus.
*/
public class MailadressenChecker extends EndlicherAutomat {
/* Bei der Implementierung dieser Klasse muss man nur
* die Attribute alphabet, uebergaenge und endzustaende
* geeignet festlegen -- alles andere macht die
* Vaterklasse.
*/
private static final char[] alphabet = new char[] {
'b', '.', '@'
};
private static final int[][] transitionen = new int[][] {
{ 0, 0, 0 },
{ 2, 2, 0 },
{ 2, 2, 3 },
{ 4, 0, 0 },
{ 4, 5, 0 },
{ 6, 0, 0 },
{ 7, 5, 0 },
{ 7, 5, 0 },
};
private static final int[] endzustaende = new int[] {
7
};
MailadressenChecker() {
// Aufruf des super-Konstruktors:
super(alphabet, transitionen, endzustaende);
}
/**
* Die main-Methode erlaubt den Aufruf des
* Binaerzahlenpruefers von der Kommandozeile mit beliebig
* vielen zu prüfenden Strings:
* java MailadressenChecker bbb.b@bb.bb a@b@c
*
* Die Ausgabe lautet dann
*
* Akzeptiert: "bbb.b@bb.bb" ist eine gültige Mailadresse.
* FEHLER! "a@b@c" ist als Mailadresse ungültig!
*/
public static void main(String[] args) {
// Endlichen Automaten instanziieren:
EndlicherAutomat checker = new MailadressenChecker();
for(String wort : args) {
if(checker.gehoertZuSprache(wort)) {
System.out.println("Akzeptiert: \"" + wort +
"\" ist eine gültige Mailadresse.");
} else {
System.out.println("FEHLER! \"" + wort +
"\" ist als Mailadresse ungültig!");
} // end if
} // end for
} // end main
} // end class

View file

@ -0,0 +1,3 @@
# Tabellen Dfa
Implementierung eines allgemeinen tabellengetriebenen DFA als Programmieraufgabe (samt einiger Beispiel-DFA).

View file

@ -0,0 +1,36 @@
Dieser Ordner enthält ein Java-Projekt, in dem die Implementierung
eines tabellengetriebenen DEA geübt wird. Es kann mit BlueJ oder
einem anderen Java-Werkzeug bearbeitet werden.
Das Projekt liegt in drei Ausstattungen vor; Sie als Lehrkraft
entscheiden, welche Variante(n) Sie den Schülern vorlegen.
Der Ordner...
.skelett
--------
enthält das Rohprojekt ohne Lösungshinweise oder Tipps, aber mit
Spezifikation, Arbeitsanweisungen und JUnit-Test. Das Projekt
sollte fehlerfrei compilieren und lauffähig sein, aber natürlich
schlagen die Tests fehl.
.tipp
-----
enthält das gleiche Projekt, aber zusätzlich mit Tipps für die
Bearbeitung durch Schüler.
.lsg
----
enthält die Musterlösung des fertig ausprogrammierten Projekts.
Hier sollten alle Tests erfolgreich laufen.
Zu bearbeiten sind die Datei EndlicherAutomat.java, in der der
eigentliche Tabellenmechanismus implementiert wird, und eine Auswahl
der Beispiel-DFA für
Mailadressen
007-Suche
oder Binärzahlen
bzw. eigene DFA für andere Sprachen nach Wahl.

View file

@ -0,0 +1,75 @@
#BlueJ package file
dependency1.from=DFA_BeispieleTest
dependency1.to=BinaerzahlenPruefer
dependency1.type=UsesDependency
dependency2.from=DFA_BeispieleTest
dependency2.to=MailadressenChecker
dependency2.type=UsesDependency
dependency3.from=DFA_BeispieleTest
dependency3.to=KGB_007Sucher
dependency3.type=UsesDependency
editor.fx.0.height=0
editor.fx.0.width=0
editor.fx.0.x=0
editor.fx.0.y=0
objectbench.height=119
objectbench.width=770
package.divider.horizontal=0.5785785785785785
package.divider.vertical=0.7519685039370079
package.editor.height=375
package.editor.width=643
package.editor.x=100
package.editor.y=100
package.frame.height=600
package.frame.width=800
package.numDependencies=3
package.numTargets=6
package.showExtends=true
package.showUses=true
project.charset=UTF-8
readme.height=58
readme.name=@README
readme.width=47
readme.x=10
readme.y=10
target1.height=62
target1.name=bin
target1.type=PackageTarget
target1.width=80
target1.x=70
target1.y=10
target2.height=50
target2.name=KGB_007Sucher
target2.showInterface=false
target2.type=ClassTarget
target2.width=140
target2.x=10
target2.y=130
target3.height=50
target3.name=DFA_BeispieleTest
target3.showInterface=false
target3.type=UnitTestTargetJunit4
target3.width=160
target3.x=180
target3.y=240
target4.height=50
target4.name=EndlicherAutomat
target4.showInterface=false
target4.type=ClassTarget
target4.width=160
target4.x=180
target4.y=30
target5.height=50
target5.name=MailadressenChecker
target5.showInterface=false
target5.type=ClassTarget
target5.width=180
target5.x=170
target5.y=130
target6.height=50
target6.name=BinaerzahlenPruefer
target6.showInterface=false
target6.type=ClassTarget
target6.width=180
target6.x=380
target6.y=130

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path=""/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER">
<attributes>
<attribute name="module" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/5"/>
<classpathentry kind="output" path="bin"/>
</classpath>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>tabellen-dfa</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View file

@ -0,0 +1,113 @@
/**
* Implementiert einen DEA, der 0/1-Folgen darauf prüft, ob
* sie "gültige Binärzahlen" darstellen.
* Gültige Binärzahlen im Sinne dieser Aufgabe beginnen mit
* einer 1, auf die eine beliebige Folge von 0/1 folgt. Die
* einzelne Ziffer 0 ist ebenfalls erlaubt, jedoch keine
* Binärzahlen mit "überflüssigen" führenden Nullen. Die
* Binärzahl darf außerdem ein Vorzeichen führen (muss aber
* nicht).
*
* Gültig sind beispielsweise:
* 1
* 0
* 101
* 11
* 10
* 1110010010
* 111
* -1
* 1000000000
* +1
* 1001001100
*
* Ungültig sind beispielsweise:
* 123
* 00
* hallo
* 0000000011111
* 1+1
* Binärzahl
* abc
* 321
* 01010101010101
* 0101
* 01
* 0101010101
*
* @author Urs Lautebach
* @version 2021-Januar
*/
public class BinaerzahlenPruefer extends EndlicherAutomat {
/* Bei der Implementierung dieser Klasse muss man nur
* die Attribute alphabet, uebergaenge und endzustaende
* geeignet festlegen -- alles andere macht die
* Vaterklasse "EndlicherAutomat.java".
*
* Dort ist auch erklärt, wie die Nummerierung der
* Zustände, des Startzustand und der Übergangstabelle
* zu verstehen sind.
*/
// Transitionstabelle anlegen mit den Zuständen auf der
// senkrechten und den Alphabetzeichen auf der Rechtsachse:
private static final int[][] transiTabelle = new int [][] {
/* die erste Zeile enthaelt die Sprünge heraus aus
* dem Fehlerzustand 0 (den der Automat ja aber gar
* nicht wieder verlassen darf), die also alle 0 sind:
*/
{ 0,0,0,0 },
{ 2,2,3,4 },
{ 0,0,3,4 },
{ 0,0,0,0 },
{ 0,0,4,4 },
};
// Alphabet für diesen Automaten als char[]
private static final char[] binaerzAlph = new char[] {
'-', '+', '0', '1'
};
// Menge der Endzustände:
private static final int[] endzustaende = new int[] {
3, 4
};
/**
* Konstruktor für einen BinaerzahlenPruefer:
*/
public BinaerzahlenPruefer() {
// Aufruf des super-Konstruktors:
super(binaerzAlph, transiTabelle, endzustaende);
}
/**
* Die main-Methode erlaubt den Aufruf von
* Binaerzahlenpruefer von der Kommandozeile aus mit
* mehreren zu testenden Strings:
*
* java BinaerzahlenPruefer 1110101 0001 +1010 abc
*
* Die Ausgabe lautet dann
* Akzeptiert: "1110101" ist ein gueltiges Binärwort.
* FEHLER! "0001" ist kein gültiges Binärwort!
* Akzeptiert: "+1010" ist ein gueltiges Binärwort.
* FEHLER! "abc" ist kein gültiges Binärwort!
*/
public static void main(String[] args) {
// Endlichen Automaten instanziieren:
EndlicherAutomat binaerzahlenDFA = new BinaerzahlenPruefer();
for(String wort : args) {
if(binaerzahlenDFA.gehoertZuSprache(wort)) {
System.out.println("Akzeptiert: \"" + wort +
"\" ist ein gültiges Binärwort.");
} else {
System.out.println("FEHLER! \"" + wort +
"\" ist kein gültiges Binärwort!");
}
}
}
}

View file

@ -0,0 +1,104 @@
import static org.junit.Assert.*;
import org.junit.Test;
public class DEA_BeispieleTest {
public DEA_BeispieleTest() {
}
@Test
public void testBinaerzahlenPruefer() {
BinaerzahlenPruefer binZPruefer = new BinaerzahlenPruefer();
assertTrue(binZPruefer.gehoertZuSprache("1"));
assertTrue(binZPruefer.gehoertZuSprache("0"));
assertTrue(binZPruefer.gehoertZuSprache("+1"));
assertTrue(binZPruefer.gehoertZuSprache("+0"));
assertTrue(binZPruefer.gehoertZuSprache("-1"));
assertTrue(binZPruefer.gehoertZuSprache("-0"));
assertTrue(binZPruefer.gehoertZuSprache("11"));
assertTrue(binZPruefer.gehoertZuSprache("10"));
assertTrue(binZPruefer.gehoertZuSprache("+11"));
assertTrue(binZPruefer.gehoertZuSprache("-11"));
assertTrue(binZPruefer.gehoertZuSprache("+10"));
assertTrue(binZPruefer.gehoertZuSprache("1111"));
assertTrue(binZPruefer.gehoertZuSprache("1000"));
assertTrue(binZPruefer.gehoertZuSprache("10100101010111000"));
assertTrue(binZPruefer.gehoertZuSprache("1111111"));
assertFalse(binZPruefer.gehoertZuSprache(""));
assertFalse(binZPruefer.gehoertZuSprache("+"));
assertFalse(binZPruefer.gehoertZuSprache("-"));
assertFalse(binZPruefer.gehoertZuSprache("x"));
assertFalse(binZPruefer.gehoertZuSprache("binärzahl"));
assertFalse(binZPruefer.gehoertZuSprache("00"));
assertFalse(binZPruefer.gehoertZuSprache("+00"));
assertFalse(binZPruefer.gehoertZuSprache("0+0"));
assertFalse(binZPruefer.gehoertZuSprache("123"));
assertFalse(binZPruefer.gehoertZuSprache("0011"));
assertFalse(binZPruefer.gehoertZuSprache("011"));
assertFalse(binZPruefer.gehoertZuSprache("111111+"));
assertFalse(binZPruefer.gehoertZuSprache("000000+"));
assertFalse(binZPruefer.gehoertZuSprache("1+1"));
assertFalse(binZPruefer.gehoertZuSprache("0+1"));
assertFalse(binZPruefer.gehoertZuSprache("1+0"));
}
@Test
public void testMailadressenChecker() {
MailadressenChecker mailAdrPruefer = new MailadressenChecker();
assertTrue(mailAdrPruefer.gehoertZuSprache("b@b.bb"));
assertTrue(mailAdrPruefer.gehoertZuSprache("b@b.bbbb"));
assertTrue(mailAdrPruefer.gehoertZuSprache("b.b.b@bbb.bbb"));
assertTrue(mailAdrPruefer.gehoertZuSprache("bbbbbb@b.bb"));
assertTrue(mailAdrPruefer.gehoertZuSprache("b@b.b.b.b.bb"));
assertTrue(mailAdrPruefer.gehoertZuSprache("...@b.bb"));
assertTrue(mailAdrPruefer.gehoertZuSprache("...bbb@bb.bb"));
assertTrue(mailAdrPruefer.gehoertZuSprache("bbb...@bb.bb"));
assertFalse(mailAdrPruefer.gehoertZuSprache(""));
assertFalse(mailAdrPruefer.gehoertZuSprache("."));
assertFalse(mailAdrPruefer.gehoertZuSprache("b"));
assertFalse(mailAdrPruefer.gehoertZuSprache("@"));
assertFalse(mailAdrPruefer.gehoertZuSprache("bb@"));
assertFalse(mailAdrPruefer.gehoertZuSprache("b@b.b@bbb"));
assertFalse(mailAdrPruefer.gehoertZuSprache("@bb"));
assertFalse(mailAdrPruefer.gehoertZuSprache("bb@."));
assertFalse(mailAdrPruefer.gehoertZuSprache("bb@.."));
assertFalse(mailAdrPruefer.gehoertZuSprache("bb@bb.b"));
assertFalse(mailAdrPruefer.gehoertZuSprache("bb@bb.bb.b"));
assertFalse(mailAdrPruefer.gehoertZuSprache("bbb@bbb"));
assertFalse(mailAdrPruefer.gehoertZuSprache("bb.bb.bb.bb"));
assertFalse(mailAdrPruefer.gehoertZuSprache(
"bbb@bb.bb.bb@bb.bb"));
assertFalse(mailAdrPruefer.gehoertZuSprache("bbb@bbb..bbb"));
assertFalse(mailAdrPruefer.gehoertZuSprache("bbb@bbb.bbb.."));
}
@Test
public void test007Sucher() {
KGB_007Sucher detektiv = new KGB_007Sucher();
assertTrue(detektiv.gehoertZuSprache("007"));
assertTrue(detektiv.gehoertZuSprache("1007"));
assertTrue(detektiv.gehoertZuSprache("0071"));
assertTrue(detektiv.gehoertZuSprache("007007"));
assertTrue(detektiv.gehoertZuSprache("00007"));
assertTrue(detektiv.gehoertZuSprache("0000712"));
assertTrue(detektiv.gehoertZuSprache("2121200777"));
assertTrue(detektiv.gehoertZuSprache("0077"));
assertTrue(detektiv.gehoertZuSprache("212121007000000"));
assertTrue(detektiv.gehoertZuSprache("00712772712717"));
assertFalse(detektiv.gehoertZuSprache(""));
assertFalse(detektiv.gehoertZuSprache("0"));
assertFalse(detektiv.gehoertZuSprache("1"));
assertFalse(detektiv.gehoertZuSprache("2"));
assertFalse(detektiv.gehoertZuSprache("7"));
assertFalse(detektiv.gehoertZuSprache("07"));
assertFalse(detektiv.gehoertZuSprache("001"));
assertFalse(detektiv.gehoertZuSprache("002"));
assertFalse(detektiv.gehoertZuSprache("000"));
assertFalse(detektiv.gehoertZuSprache("001002"));
assertFalse(detektiv.gehoertZuSprache("7001"));
assertFalse(detektiv.gehoertZuSprache("0707"));
}
}

View file

@ -0,0 +1,196 @@
/**
* Implementiert einen tabellengetriebenen endlichen Automaten.
* Instanzen dieser Klasse sind DEAs, die Wörter über einem
* vorgegebenen Alphabet akzeptieren oder ablehnen können.
*
* Die Aufgabe wurde vom schriftlichen Abitur 2020 in
* Baden-Württemberg inspiriert.
*
* @author Urs Lautebach
* @version 2020-Oktober
*/
public class EndlicherAutomat {
private int [][] uebergaenge = null;
private int[] endzustaende = null;
private char[] alphabet = null;
/**
* Konstruiert einen tabellengetriebenen DEA. Nach dem
* erfolgreichen Aufruf dieses Konstruktors kann man den DEA
* anschließend durch einen Aufruf der Methode
* gehoertZuSprache(String):boolean
* beliebig viele Wörter testen lassen.
*
* @param tabelle Transitionstabelle des DEA. Die erste
* Dimension bezeichnet die Zustände; die zweite Dimension die
* Eingabezeichen. Die Einträge der Tabelle bezeichnen jeweils
* den Zustand, in den der Automat (abhängig vom vorherigen
* Zustand und der Eingabe) wechseln soll.
*
* Der Zustand 0 gilt als Fehlerzustand. Zustand 1 ist immer
* Startzustand (so dass der Startzustand, anders als bei der
* formalen Beschreibung eines DEA, nicht explizit angegeben
* werden muss).
*
* @param finalStates Ein int[], das die Endzustände enthält.
*
* @param alphabet ein Array von char, das das Alphabet des
* Automaten enthält. Die Reihenfolge der Zeichen im Alphabet
* muss der Reihenfolge der Zeichen an der entsprechenden
* Achse der Transitionstabelle entsprechen.
*/
EndlicherAutomat(final char[] alphabet,
final int[][] uebergaenge, final int[] endzustaende ) {
this.alphabet = alphabet;
this.uebergaenge = uebergaenge;
this.endzustaende = endzustaende;
// Die Methode plausibilitaetPruefen ist fertig vorgegeben;
// sie fängt einige offensichtliche Fehler ab:
plausibilitaetPruefen();
}
/**
* Die Methode prüft, ob die Attribute transitionstabelle,
* alphabet und endzustaende zueinander passen. Sie ist fertig
* implementiert und dafür gedacht, am Ende des Konstruktors
* aufgerufen zu werden.
*/
private void plausibilitaetPruefen() {
if (uebergaenge == null) {
throw new IllegalArgumentException(
"Die Übergangstabelle ist null oder leer!");
}
if (alphabet == null) {
throw new IllegalArgumentException(
"Das Alphabet ist null oder leer!");
}
if (endzustaende == null) {
throw new IllegalArgumentException(
"endzustaende ist null oder leer!");
}
int tabelleHoehe = this.uebergaenge.length;
int tabelleBreite = uebergaenge[0].length;
// Hat die Übergangstabelle eine Zeile pro Alphabetzeichen?
if (tabelleBreite != alphabet.length) {
throw new IllegalArgumentException("Das Alphabet hat " +
alphabet.length + " Zeichen, die " +
" Übergangstabelle aber " + tabelleBreite +
" Spalten!");
}
// Sind alle Zeilen der Transitionstabelle gleich lang?
for (int[] zeile : uebergaenge) {
if (zeile.length != tabelleBreite) {
throw new IllegalArgumentException(
"Übergangstabelle ist nicht rechteckig!");
}
}
// Hat einer der Endzustände eine unplausible Nummer?
for (int zustand : endzustaende) {
if (zustand < 1 || zustand > tabelleHoehe - 1) {
throw new IllegalArgumentException(
"Der Endzustand " + zustand +
" kommt in der Übergangstabelle nicht vor!");
}
}
}
/**
* Ermittelt die Nummer (den Index) des angegebenen Zeichens
* innerhalb des Alphabetes dieses Automaten.
*
* @param input Zeichen, dessen Position ermittelt werden soll.
* @returns Position des Zeichens input innerhalb des Alphabets
* dieses Automaten; oder -1, falls es im Alphabet nicht
* enthalten ist.
*/
public int indexImAlphabet(char input) {
/* Man geht das Alphabet durch und prüft, welches seiner
* Zeichen dem "input" entspricht. Falls man es findet,
* gibt man dessen Index zurück.
*/
for (int index = 0; index < alphabet.length; index++) {
if (input == alphabet[index])
return index;
}
return -1;
}
/**
* Überprüft, ob der Zustand mit der übergebenen
* Zustandsnummer einer der Endzustände dieses Automaten ist.
*
* @param nr Nummer des fraglichen Zustandes.
* @return ob der Zustand ein Endzustand ist.
*/
public boolean istEndzustand(int nr) {
for (int endzustand : endzustaende) {
// Gehe durch alle Endzustände. Wenn nr einer ist...
if (nr == endzustand) {
return true;
}
}
return false;
}
/**
* Die Methode kann mit einem String als Parameter aufgerufen
* werden, was oft bequemer ist als ein char[].
*
* @param s String mit dem zu prüfenden Wort.
* @return ob s von diesem Automaten erkannt wird.
*/
public boolean gehoertZuSprache(String s) {
// Hier ist nichts zu implementieren.
return gehoertZuSprache(s.toCharArray());
}
/**
* Übergibt dem DEA ein ganzes Wort und ermittelt, ob er es
* akzeptiert oder nicht.
*
* @param eingabe Die komplette zu analysierende Eingabe als
* char[].
* @returns true, wenn das Wort vom DEA akzeptiert wird;
* false sonst.
*/
public boolean gehoertZuSprache(final char[] wort) {
/*
* Um zu prüfen, ob wort akzeptiert wird, muss der DEA...
*
* - in Zustand 1 beginnen;
*
* - das Eingabewort Zeichen für Zeichen durchgehen;
*
* - prüfen, ob das Zeichen im Alphabet vorkommt;
*
* - nach dessen Position im Alphabet und altem Zustand
* einen neuen Zustand aus der Tabelle uebergaenge wählen;
*
* - false antworten, wenn er im Fehlerzustand landet,
*
* - am Schluss der Eingabe entscheiden, ob der erreichte
* Zustand ein Endzustand ist.
*/
// Startzustand ist immer Nr. 1:
int zustand = 1;
// Gehe durch alle Zeichen durch:
for (char zeichen : wort) {
int alphIndex = indexImAlphabet(zeichen);
// Falls das Zeichen gar nicht im Alphabet ist...:
if (alphIndex == -1) {
return false;
} else {
// wechsle in neuen Zustand:
zustand = uebergaenge[zustand][alphIndex];
}
// Bin ich im Fehlerzustand?
if (zustand == 0) {
return false;
}
}
// Die Eingabe ist verbraucht. Falls der aktuelle Zustand
// ein Endzustand ist, akzeptieren wir die Eingabe:
return istEndzustand(zustand);
}
}

View file

@ -0,0 +1,92 @@
/**
* Dieser DFA erkennt Ziffernfolgen, in denen sich irgendwo
* James Bond versteckt hat -- in denen also die Folge 007
* vorkommt.
*
* Die folgenden Ziffernfolgen sollen beispielsweise akzeptiert
* werden:
*
* 12107117700710012021,
* 007,
* 0071121727,
* 0000000071121727,
* 007007007007,
* 1121271201212007.
*
* Die folgenden Ziffernfolgen sollen nicht akzeptiert werden:
*
* 12107110710012021,
* 07,
* 00,
* 07112172,
* 1121271201212000.
* Um den Automaten und vor allem die Übergangstabelle
* übersichtlicher zu halten, verwendet er nicht alle Ziffern,
* sondern lediglich das eingeschränkte Alphabet {0, 1, 2, 7}.
*
* Es empfiehlt sich, den Automaten zunächst zu zeichnen,
* die Übergangstabelle auf Papier zu erstellen und dann zu
* programmieren.
*
* @author Urs Lautebach
* @version 2020-Okt
*/
public class KGB_007Sucher extends EndlicherAutomat {
/* Bei der Implementierung dieser Klasse muss man nur
* die Attribute alphabet, uebergaenge und endzustaende
* geeignet festlegen -- alles andere macht die
* Vaterklasse.
*/
private static final char[] alphabet = new char[] {
'0', '1', '2', '7'
};
private static final int[][] uebergaenge = new int[][] {
{ 0, 0, 0, 0 },
{ 2, 1, 1, 1 },
{ 3, 1, 1, 1 },
{ 3, 1, 1, 4 },
{ 4, 4, 4, 4 },
};
private static final int[] endzustaende = new int[] {
4
};
/**
* Instanziiert einen KGB_007Sucher-DFA.
*/
KGB_007Sucher() {
// Aufruf des super-Konstruktors:
super(alphabet, uebergaenge, endzustaende);
}
/**
* Die main-Methode erlaubt den Aufruf des
* Binaerzahlenpruefers von der Kommandozeile aus mit:
*
* java KGB_007Sucher 127007117 1717771021
*
* Die Ausgabe lautet dann
*
* Akzeptiert: "127007117" enthält 007.
* FEHLER! "1717771021" enthält kein 007!
*/
public static void main(String[] args) {
// Endlichen Automaten instanziieren:
EndlicherAutomat fahnder = new KGB_007Sucher();
for(String wort : args) {
if(fahnder.gehoertZuSprache(wort)) {
System.out.println("Akzeptiert: \"" + wort +
"\" enthält 007.");
} else {
System.out.println("FEHLER! \"" + wort +
"\" enthält kein 007!");
}
}
}
}

View file

@ -0,0 +1,93 @@
/**
* Die Klasse implementiert einen DEA für die Überprüfung äußerst
* einfacher Mailadressen, die nur aus dem Buchstaben b, Punkten
* und dem at-Zeichen bestehen dürfen. Der Nutzername darf fast
* beliebig aufgebaut sein; die Domain muss mindestens zweistufig
* sein und die Toplevel-Domain muss mindestens zwei Zeichen haben.
*
* Gültig sind damit beispielsweise:
* b@b.bb
* b@b.bbbb
* b.b.b@bbb.bbb
* bbbbbb@b.bb
* b@b.b.b.b.bb
* ...@b.bb
* ...bbb@bb.bb
* bbb...@bb.bb
*
* Ungültig sind beispielsweise:
* .
* b
* @
* bb@
* b@b.b@bbb
* b@b.b@bb.b
* @bb
* bb@.
* bb@..
*
* Tatsächlich ist die Überprüfung realer Mailadressen wesentlich
* komlizierter als in diesem Beispiel.
*
* @author Urs Lautebach
* @version 2021-Janar
*
*/
public class MailadressenChecker extends EndlicherAutomat {
/* Bei der Implementierung dieser Klasse muss man nur
* die Attribute alphabet, uebergaenge und endzustaende
* geeignet festlegen -- alles andere macht die
* Vaterklasse.
*/
private static final char[] alphabet = new char[] {
'b', '.', '@'
};
private static final int[][] transitionen = new int[][] {
{ 0, 0, 0 },
{ 2, 2, 0 },
{ 2, 2, 3 },
{ 4, 0, 0 },
{ 4, 5, 0 },
{ 6, 0, 0 },
{ 7, 5, 0 },
{ 7, 5, 0 },
};
private static final int[] endzustaende = new int[] {
7
};
MailadressenChecker() {
// Aufruf des super-Konstruktors:
super(alphabet, transitionen, endzustaende);
}
/**
* Die main-Methode erlaubt den Aufruf des
* Binaerzahlenpruefers von der Kommandozeile mit beliebig
* vielen zu prüfenden Strings:
* java MailadressenChecker bbb.b@bb.bb a@b@c
*
* Die Ausgabe lautet dann
*
* Akzeptiert: "bbb.b@bb.bb" ist eine gültige Mailadresse.
* FEHLER! "a@b@c" ist als Mailadresse ungültig!
*/
public static void main(String[] args) {
// Endlichen Automaten instanziieren:
EndlicherAutomat checker = new MailadressenChecker();
for(String wort : args) {
if(checker.gehoertZuSprache(wort)) {
System.out.println("Akzeptiert: \"" + wort +
"\" ist eine gültige Mailadresse.");
} else {
System.out.println("FEHLER! \"" + wort +
"\" ist als Mailadresse ungültig!");
} // end if
} // end for
} // end main
} // end class

View file

@ -0,0 +1,3 @@
# Tabellen Dfa
Implementierung eines allgemeinen tabellengetriebenen DFA als Programmieraufgabe (samt einiger Beispiel-DFA).

View file

@ -0,0 +1,36 @@
Dieser Ordner enthält ein Java-Projekt, in dem die Implementierung
eines tabellengetriebenen DEA geübt wird. Es kann mit BlueJ oder
einem anderen Java-Werkzeug bearbeitet werden.
Das Projekt liegt in drei Ausstattungen vor; Sie als Lehrkraft
entscheiden, welche Variante(n) Sie den Schülern vorlegen.
Der Ordner...
.skelett
--------
enthält das Rohprojekt ohne Lösungshinweise oder Tipps, aber mit
Spezifikation, Arbeitsanweisungen und JUnit-Test. Das Projekt
sollte fehlerfrei compilieren und lauffähig sein, aber natürlich
schlagen die Tests fehl.
.tipp
-----
enthält das gleiche Projekt, aber zusätzlich mit Tipps für die
Bearbeitung durch Schüler.
.lsg
----
enthält die Musterlösung des fertig ausprogrammierten Projekts.
Hier sollten alle Tests erfolgreich laufen.
Zu bearbeiten sind die Datei EndlicherAutomat.java, in der der
eigentliche Tabellenmechanismus implementiert wird, und eine Auswahl
der Beispiel-DFA für
Mailadressen
007-Suche
oder Binärzahlen
bzw. eigene DFA für andere Sprachen nach Wahl.

View file

@ -0,0 +1,75 @@
#BlueJ package file
dependency1.from=DFA_BeispieleTest
dependency1.to=BinaerzahlenPruefer
dependency1.type=UsesDependency
dependency2.from=DFA_BeispieleTest
dependency2.to=MailadressenChecker
dependency2.type=UsesDependency
dependency3.from=DFA_BeispieleTest
dependency3.to=KGB_007Sucher
dependency3.type=UsesDependency
editor.fx.0.height=0
editor.fx.0.width=0
editor.fx.0.x=0
editor.fx.0.y=0
objectbench.height=119
objectbench.width=770
package.divider.horizontal=0.5785785785785785
package.divider.vertical=0.7519685039370079
package.editor.height=375
package.editor.width=643
package.editor.x=100
package.editor.y=100
package.frame.height=600
package.frame.width=800
package.numDependencies=3
package.numTargets=6
package.showExtends=true
package.showUses=true
project.charset=UTF-8
readme.height=58
readme.name=@README
readme.width=47
readme.x=10
readme.y=10
target1.height=62
target1.name=bin
target1.type=PackageTarget
target1.width=80
target1.x=70
target1.y=10
target2.height=50
target2.name=KGB_007Sucher
target2.showInterface=false
target2.type=ClassTarget
target2.width=140
target2.x=10
target2.y=130
target3.height=50
target3.name=DFA_BeispieleTest
target3.showInterface=false
target3.type=UnitTestTargetJunit4
target3.width=160
target3.x=180
target3.y=240
target4.height=50
target4.name=EndlicherAutomat
target4.showInterface=false
target4.type=ClassTarget
target4.width=160
target4.x=180
target4.y=30
target5.height=50
target5.name=MailadressenChecker
target5.showInterface=false
target5.type=ClassTarget
target5.width=180
target5.x=170
target5.y=130
target6.height=50
target6.name=BinaerzahlenPruefer
target6.showInterface=false
target6.type=ClassTarget
target6.width=180
target6.x=380
target6.y=130

View file

@ -0,0 +1,11 @@
= Material :
|===
|Zuordnung|
|Klassenstufe|
|Bildungsplanbezug |
|Werkzeug|
|Autoren|
|===
== Inhalt

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path=""/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER">
<attributes>
<attribute name="module" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/5"/>
<classpathentry kind="output" path="bin"/>
</classpath>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>tabellen-dfa</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View file

@ -0,0 +1,93 @@
/**
* Implementiert einen DEA, der 0/1-Folgen darauf prüft, ob
* sie "gültige Binärzahlen" darstellen.
* Gültige Binärzahlen im Sinne dieser Aufgabe beginnen mit
* einer 1, auf die eine beliebige Folge von 0/1 folgt. Die
* einzelne Ziffer 0 ist ebenfalls erlaubt, jedoch keine
* Binärzahlen mit "überflüssigen" führenden Nullen. Die
* Binärzahl darf außerdem ein Vorzeichen führen (muss aber
* nicht).
*
* Gültig sind beispielsweise:
* 1
* 0
* 101
* 11
* 10
* 1110010010
* 111
* -1
* 1000000000
* +1
* 1001001100
*
* Ungültig sind beispielsweise:
* 123
* 00
* hallo
* 0000000011111
* 1+1
* Binärzahl
* abc
* 321
* 01010101010101
* 0101
* 01
* 0101010101
*
* @author Urs Lautebach
* @version 2021-Januar
*/
public class BinaerzahlenPruefer extends EndlicherAutomat {
// Transitionstabelle anlegen mit den Zuständen auf der
// senkrechten und den Alphabetzeichen auf der Rechtsachse:
private static final int[][] transiTabelle = new int [][] {
};
// Alphabet für diesen Automaten als char[]
private static final char[] binaerzAlph = new char[] {
};
// Menge der Endzustände:
private static final int[] endzustaende = new int[] {
};
/**
* Konstruktor für einen BinaerzahlenPruefer:
*/
public BinaerzahlenPruefer() {
// Aufruf des super-Konstruktors:
super(binaerzAlph, transiTabelle, endzustaende);
}
/**
* Die main-Methode erlaubt den Aufruf von
* Binaerzahlenpruefer von der Kommandozeile aus mit
* mehreren zu testenden Strings:
*
* java BinaerzahlenPruefer 1110101 0001 +1010 abc
*
* Die Ausgabe lautet dann
* Akzeptiert: "1110101" ist ein gueltiges Binärwort.
* FEHLER! "0001" ist kein gültiges Binärwort!
* Akzeptiert: "+1010" ist ein gueltiges Binärwort.
* FEHLER! "abc" ist kein gültiges Binärwort!
*/
public static void main(String[] args) {
// Endlichen Automaten instanziieren:
EndlicherAutomat binaerzahlenDFA = new BinaerzahlenPruefer();
for(String wort : args) {
if(binaerzahlenDFA.gehoertZuSprache(wort)) {
System.out.println("Akzeptiert: \"" + wort +
"\" ist ein gültiges Binärwort.");
} else {
System.out.println("FEHLER! \"" + wort +
"\" ist kein gültiges Binärwort!");
}
}
}
}

View file

@ -0,0 +1,104 @@
import static org.junit.Assert.*;
import org.junit.Test;
public class DEA_BeispieleTest {
public DEA_BeispieleTest() {
}
@Test
public void testBinaerzahlenPruefer() {
BinaerzahlenPruefer binZPruefer = new BinaerzahlenPruefer();
assertTrue(binZPruefer.gehoertZuSprache("1"));
assertTrue(binZPruefer.gehoertZuSprache("0"));
assertTrue(binZPruefer.gehoertZuSprache("+1"));
assertTrue(binZPruefer.gehoertZuSprache("+0"));
assertTrue(binZPruefer.gehoertZuSprache("-1"));
assertTrue(binZPruefer.gehoertZuSprache("-0"));
assertTrue(binZPruefer.gehoertZuSprache("11"));
assertTrue(binZPruefer.gehoertZuSprache("10"));
assertTrue(binZPruefer.gehoertZuSprache("+11"));
assertTrue(binZPruefer.gehoertZuSprache("-11"));
assertTrue(binZPruefer.gehoertZuSprache("+10"));
assertTrue(binZPruefer.gehoertZuSprache("1111"));
assertTrue(binZPruefer.gehoertZuSprache("1000"));
assertTrue(binZPruefer.gehoertZuSprache("10100101010111000"));
assertTrue(binZPruefer.gehoertZuSprache("1111111"));
assertFalse(binZPruefer.gehoertZuSprache(""));
assertFalse(binZPruefer.gehoertZuSprache("+"));
assertFalse(binZPruefer.gehoertZuSprache("-"));
assertFalse(binZPruefer.gehoertZuSprache("x"));
assertFalse(binZPruefer.gehoertZuSprache("binärzahl"));
assertFalse(binZPruefer.gehoertZuSprache("00"));
assertFalse(binZPruefer.gehoertZuSprache("+00"));
assertFalse(binZPruefer.gehoertZuSprache("0+0"));
assertFalse(binZPruefer.gehoertZuSprache("123"));
assertFalse(binZPruefer.gehoertZuSprache("0011"));
assertFalse(binZPruefer.gehoertZuSprache("011"));
assertFalse(binZPruefer.gehoertZuSprache("111111+"));
assertFalse(binZPruefer.gehoertZuSprache("000000+"));
assertFalse(binZPruefer.gehoertZuSprache("1+1"));
assertFalse(binZPruefer.gehoertZuSprache("0+1"));
assertFalse(binZPruefer.gehoertZuSprache("1+0"));
}
@Test
public void testMailadressenChecker() {
MailadressenChecker mailAdrPruefer = new MailadressenChecker();
assertTrue(mailAdrPruefer.gehoertZuSprache("b@b.bb"));
assertTrue(mailAdrPruefer.gehoertZuSprache("b@b.bbbb"));
assertTrue(mailAdrPruefer.gehoertZuSprache("b.b.b@bbb.bbb"));
assertTrue(mailAdrPruefer.gehoertZuSprache("bbbbbb@b.bb"));
assertTrue(mailAdrPruefer.gehoertZuSprache("b@b.b.b.b.bb"));
assertTrue(mailAdrPruefer.gehoertZuSprache("...@b.bb"));
assertTrue(mailAdrPruefer.gehoertZuSprache("...bbb@bb.bb"));
assertTrue(mailAdrPruefer.gehoertZuSprache("bbb...@bb.bb"));
assertFalse(mailAdrPruefer.gehoertZuSprache(""));
assertFalse(mailAdrPruefer.gehoertZuSprache("."));
assertFalse(mailAdrPruefer.gehoertZuSprache("b"));
assertFalse(mailAdrPruefer.gehoertZuSprache("@"));
assertFalse(mailAdrPruefer.gehoertZuSprache("bb@"));
assertFalse(mailAdrPruefer.gehoertZuSprache("b@b.b@bbb"));
assertFalse(mailAdrPruefer.gehoertZuSprache("@bb"));
assertFalse(mailAdrPruefer.gehoertZuSprache("bb@."));
assertFalse(mailAdrPruefer.gehoertZuSprache("bb@.."));
assertFalse(mailAdrPruefer.gehoertZuSprache("bb@bb.b"));
assertFalse(mailAdrPruefer.gehoertZuSprache("bb@bb.bb.b"));
assertFalse(mailAdrPruefer.gehoertZuSprache("bbb@bbb"));
assertFalse(mailAdrPruefer.gehoertZuSprache("bb.bb.bb.bb"));
assertFalse(mailAdrPruefer.gehoertZuSprache(
"bbb@bb.bb.bb@bb.bb"));
assertFalse(mailAdrPruefer.gehoertZuSprache("bbb@bbb..bbb"));
assertFalse(mailAdrPruefer.gehoertZuSprache("bbb@bbb.bbb.."));
}
@Test
public void test007Sucher() {
KGB_007Sucher detektiv = new KGB_007Sucher();
assertTrue(detektiv.gehoertZuSprache("007"));
assertTrue(detektiv.gehoertZuSprache("1007"));
assertTrue(detektiv.gehoertZuSprache("0071"));
assertTrue(detektiv.gehoertZuSprache("007007"));
assertTrue(detektiv.gehoertZuSprache("00007"));
assertTrue(detektiv.gehoertZuSprache("0000712"));
assertTrue(detektiv.gehoertZuSprache("2121200777"));
assertTrue(detektiv.gehoertZuSprache("0077"));
assertTrue(detektiv.gehoertZuSprache("212121007000000"));
assertTrue(detektiv.gehoertZuSprache("00712772712717"));
assertFalse(detektiv.gehoertZuSprache(""));
assertFalse(detektiv.gehoertZuSprache("0"));
assertFalse(detektiv.gehoertZuSprache("1"));
assertFalse(detektiv.gehoertZuSprache("2"));
assertFalse(detektiv.gehoertZuSprache("7"));
assertFalse(detektiv.gehoertZuSprache("07"));
assertFalse(detektiv.gehoertZuSprache("001"));
assertFalse(detektiv.gehoertZuSprache("002"));
assertFalse(detektiv.gehoertZuSprache("000"));
assertFalse(detektiv.gehoertZuSprache("001002"));
assertFalse(detektiv.gehoertZuSprache("7001"));
assertFalse(detektiv.gehoertZuSprache("0707"));
}
}

View file

@ -0,0 +1,146 @@
/**
* Implementiert einen tabellengetriebenen endlichen Automaten.
* Instanzen dieser Klasse sind DEAs, die Wörter über einem
* vorgegebenen Alphabet akzeptieren oder ablehnen können.
*
* Die Aufgabe wurde vom schriftlichen Abitur 2020 in
* Baden-Württemberg inspiriert.
*
* @author Urs Lautebach
* @version 2020-Oktober
*/
public class EndlicherAutomat {
private int [][] uebergaenge = null;
private int[] endzustaende = null;
private char[] alphabet = null;
/**
* Konstruiert einen tabellengetriebenen DEA. Nach dem
* erfolgreichen Aufruf dieses Konstruktors kann man den DEA
* anschließend durch einen Aufruf der Methode
* gehoertZuSprache(String):boolean
* beliebig viele Wörter testen lassen.
*
* @param tabelle Transitionstabelle des DEA. Die erste
* Dimension bezeichnet die Zustände; die zweite Dimension die
* Eingabezeichen. Die Einträge der Tabelle bezeichnen jeweils
* den Zustand, in den der Automat (abhängig vom vorherigen
* Zustand und der Eingabe) wechseln soll.
*
* Der Zustand 0 gilt als Fehlerzustand. Zustand 1 ist immer
* Startzustand (so dass der Startzustand, anders als bei der
* formalen Beschreibung eines DEA, nicht explizit angegeben
* werden muss).
*
* @param finalStates Ein int[], das die Endzustände enthält.
*
* @param alphabet ein Array von char, das das Alphabet des
* Automaten enthält. Die Reihenfolge der Zeichen im Alphabet
* muss der Reihenfolge der Zeichen an der entsprechenden
* Achse der Transitionstabelle entsprechen.
*/
EndlicherAutomat(final char[] alphabet,
final int[][] uebergaenge, final int[] endzustaende ) {
// Die Methode plausibilitaetPruefen ist fertig vorgegeben;
// sie fängt einige offensichtliche Fehler ab:
plausibilitaetPruefen();
}
/**
* Die Methode prüft, ob die Attribute transitionstabelle,
* alphabet und endzustaende zueinander passen. Sie ist fertig
* implementiert und dafür gedacht, am Ende des Konstruktors
* aufgerufen zu werden.
*/
private void plausibilitaetPruefen() {
if (uebergaenge == null) {
throw new IllegalArgumentException(
"Die Übergangstabelle ist null oder leer!");
}
if (alphabet == null) {
throw new IllegalArgumentException(
"Das Alphabet ist null oder leer!");
}
if (endzustaende == null) {
throw new IllegalArgumentException(
"endzustaende ist null oder leer!");
}
int tabelleHoehe = this.uebergaenge.length;
int tabelleBreite = uebergaenge[0].length;
// Hat die Übergangstabelle eine Zeile pro Alphabetzeichen?
if (tabelleBreite != alphabet.length) {
throw new IllegalArgumentException("Das Alphabet hat " +
alphabet.length + " Zeichen, die " +
" Übergangstabelle aber " + tabelleBreite +
" Spalten!");
}
// Sind alle Zeilen der Transitionstabelle gleich lang?
for (int[] zeile : uebergaenge) {
if (zeile.length != tabelleBreite) {
throw new IllegalArgumentException(
"Übergangstabelle ist nicht rechteckig!");
}
}
// Hat einer der Endzustände eine unplausible Nummer?
for (int zustand : endzustaende) {
if (zustand < 1 || zustand > tabelleHoehe - 1) {
throw new IllegalArgumentException(
"Der Endzustand " + zustand +
" kommt in der Übergangstabelle nicht vor!");
}
}
}
/**
* Ermittelt die Nummer (den Index) des angegebenen Zeichens
* innerhalb des Alphabetes dieses Automaten.
*
* @param input Zeichen, dessen Position ermittelt werden soll.
* @returns Position des Zeichens input innerhalb des Alphabets
* dieses Automaten; oder -1, falls es im Alphabet nicht
* enthalten ist.
*/
public int indexImAlphabet(char input) {
// TODO: Implementieren Sie diese Methode.
return -54321; // dummy return
}
/**
* Überprüft, ob der Zustand mit der übergebenen
* Zustandsnummer einer der Endzustände dieses Automaten ist.
*
* @param nr Nummer des fraglichen Zustandes.
* @return ob der Zustand ein Endzustand ist.
*/
public boolean istEndzustand(int nr) {
// TODO: Implementieren Sie diese Methode.
return false; // dummy return
}
/**
* Die Methode kann mit einem String als Parameter aufgerufen
* werden, was oft bequemer ist als ein char[].
*
* @param s String mit dem zu prüfenden Wort.
* @return ob s von diesem Automaten erkannt wird.
*/
public boolean gehoertZuSprache(String s) {
// Hier ist nichts zu implementieren.
return gehoertZuSprache(s.toCharArray());
}
/**
* Übergibt dem DEA ein ganzes Wort und ermittelt, ob er es
* akzeptiert oder nicht.
*
* @param eingabe Die komplette zu analysierende Eingabe als
* char[].
* @returns true, wenn das Wort vom DEA akzeptiert wird;
* false sonst.
*/
public boolean gehoertZuSprache(final char[] wort) {
// TODO: Implementieren Sie diese Methode.
return false; // dummy return
}
}

View file

@ -0,0 +1,80 @@
/**
* Dieser DFA erkennt Ziffernfolgen, in denen sich irgendwo
* James Bond versteckt hat -- in denen also die Folge 007
* vorkommt.
*
* Die folgenden Ziffernfolgen sollen beispielsweise akzeptiert
* werden:
*
* 12107117700710012021,
* 007,
* 0071121727,
* 0000000071121727,
* 007007007007,
* 1121271201212007.
*
* Die folgenden Ziffernfolgen sollen nicht akzeptiert werden:
*
* 12107110710012021,
* 07,
* 00,
* 07112172,
* 1121271201212000.
* Um den Automaten und vor allem die Übergangstabelle
* übersichtlicher zu halten, verwendet er nicht alle Ziffern,
* sondern lediglich das eingeschränkte Alphabet {0, 1, 2, 7}.
*
* Es empfiehlt sich, den Automaten zunächst zu zeichnen,
* die Übergangstabelle auf Papier zu erstellen und dann zu
* programmieren.
*
* @author Urs Lautebach
* @version 2020-Okt
*/
public class KGB_007Sucher extends EndlicherAutomat {
private static final char[] alphabet = new char[] {
};
private static final int[][] uebergaenge = new int[][] {
};
private static final int[] endzustaende = new int[] {
};
/**
* Instanziiert einen KGB_007Sucher-DFA.
*/
KGB_007Sucher() {
// Aufruf des super-Konstruktors:
super(alphabet, uebergaenge, endzustaende);
}
/**
* Die main-Methode erlaubt den Aufruf des
* Binaerzahlenpruefers von der Kommandozeile aus mit:
*
* java KGB_007Sucher 127007117 1717771021
*
* Die Ausgabe lautet dann
*
* Akzeptiert: "127007117" enthält 007.
* FEHLER! "1717771021" enthält kein 007!
*/
public static void main(String[] args) {
// Endlichen Automaten instanziieren:
EndlicherAutomat fahnder = new KGB_007Sucher();
for(String wort : args) {
if(fahnder.gehoertZuSprache(wort)) {
System.out.println("Akzeptiert: \"" + wort +
"\" enthält 007.");
} else {
System.out.println("FEHLER! \"" + wort +
"\" enthält kein 007!");
}
}
}
}

View file

@ -0,0 +1,78 @@
/**
* Die Klasse implementiert einen DEA für die Überprüfung äußerst
* einfacher Mailadressen, die nur aus dem Buchstaben b, Punkten
* und dem at-Zeichen bestehen dürfen. Der Nutzername darf fast
* beliebig aufgebaut sein; die Domain muss mindestens zweistufig
* sein und die Toplevel-Domain muss mindestens zwei Zeichen haben.
*
* Gültig sind damit beispielsweise:
* b@b.bb
* b@b.bbbb
* b.b.b@bbb.bbb
* bbbbbb@b.bb
* b@b.b.b.b.bb
* ...@b.bb
* ...bbb@bb.bb
* bbb...@bb.bb
*
* Ungültig sind beispielsweise:
* .
* b
* @
* bb@
* b@b.b@bbb
* b@b.b@bb.b
* @bb
* bb@.
* bb@..
*
* Tatsächlich ist die Überprüfung realer Mailadressen wesentlich
* komlizierter als in diesem Beispiel.
*
* @author Urs Lautebach
* @version 2021-Janar
*
*/
public class MailadressenChecker extends EndlicherAutomat {
private static final char[] alphabet = new char[] {
};
private static final int[][] transitionen = new int[][] {
};
private static final int[] endzustaende = new int[] {
};
MailadressenChecker() {
// Aufruf des super-Konstruktors:
super(alphabet, transitionen, endzustaende);
}
/**
* Die main-Methode erlaubt den Aufruf des
* Binaerzahlenpruefers von der Kommandozeile mit beliebig
* vielen zu prüfenden Strings:
* java MailadressenChecker bbb.b@bb.bb a@b@c
*
* Die Ausgabe lautet dann
*
* Akzeptiert: "bbb.b@bb.bb" ist eine gültige Mailadresse.
* FEHLER! "a@b@c" ist als Mailadresse ungültig!
*/
public static void main(String[] args) {
// Endlichen Automaten instanziieren:
EndlicherAutomat checker = new MailadressenChecker();
for(String wort : args) {
if(checker.gehoertZuSprache(wort)) {
System.out.println("Akzeptiert: \"" + wort +
"\" ist eine gültige Mailadresse.");
} else {
System.out.println("FEHLER! \"" + wort +
"\" ist als Mailadresse ungültig!");
} // end if
} // end for
} // end main
} // end class

View file

@ -0,0 +1,3 @@
# Tabellen Dfa
Implementierung eines allgemeinen tabellengetriebenen DFA als Programmieraufgabe (samt einiger Beispiel-DFA).

View file

@ -0,0 +1,36 @@
Dieser Ordner enthält ein Java-Projekt, in dem die Implementierung
eines tabellengetriebenen DEA geübt wird. Es kann mit BlueJ oder
einem anderen Java-Werkzeug bearbeitet werden.
Das Projekt liegt in drei Ausstattungen vor; Sie als Lehrkraft
entscheiden, welche Variante(n) Sie den Schülern vorlegen.
Der Ordner...
.skelett
--------
enthält das Rohprojekt ohne Lösungshinweise oder Tipps, aber mit
Spezifikation, Arbeitsanweisungen und JUnit-Test. Das Projekt
sollte fehlerfrei compilieren und lauffähig sein, aber natürlich
schlagen die Tests fehl.
.tipp
-----
enthält das gleiche Projekt, aber zusätzlich mit Tipps für die
Bearbeitung durch Schüler.
.lsg
----
enthält die Musterlösung des fertig ausprogrammierten Projekts.
Hier sollten alle Tests erfolgreich laufen.
Zu bearbeiten sind die Datei EndlicherAutomat.java, in der der
eigentliche Tabellenmechanismus implementiert wird, und eine Auswahl
der Beispiel-DFA für
Mailadressen
007-Suche
oder Binärzahlen
bzw. eigene DFA für andere Sprachen nach Wahl.

View file

@ -0,0 +1,75 @@
#BlueJ package file
dependency1.from=DFA_BeispieleTest
dependency1.to=BinaerzahlenPruefer
dependency1.type=UsesDependency
dependency2.from=DFA_BeispieleTest
dependency2.to=MailadressenChecker
dependency2.type=UsesDependency
dependency3.from=DFA_BeispieleTest
dependency3.to=KGB_007Sucher
dependency3.type=UsesDependency
editor.fx.0.height=0
editor.fx.0.width=0
editor.fx.0.x=0
editor.fx.0.y=0
objectbench.height=119
objectbench.width=770
package.divider.horizontal=0.5785785785785785
package.divider.vertical=0.7519685039370079
package.editor.height=375
package.editor.width=643
package.editor.x=100
package.editor.y=100
package.frame.height=600
package.frame.width=800
package.numDependencies=3
package.numTargets=6
package.showExtends=true
package.showUses=true
project.charset=UTF-8
readme.height=58
readme.name=@README
readme.width=47
readme.x=10
readme.y=10
target1.height=62
target1.name=bin
target1.type=PackageTarget
target1.width=80
target1.x=70
target1.y=10
target2.height=50
target2.name=KGB_007Sucher
target2.showInterface=false
target2.type=ClassTarget
target2.width=140
target2.x=10
target2.y=130
target3.height=50
target3.name=DFA_BeispieleTest
target3.showInterface=false
target3.type=UnitTestTargetJunit4
target3.width=160
target3.x=180
target3.y=240
target4.height=50
target4.name=EndlicherAutomat
target4.showInterface=false
target4.type=ClassTarget
target4.width=160
target4.x=180
target4.y=30
target5.height=50
target5.name=MailadressenChecker
target5.showInterface=false
target5.type=ClassTarget
target5.width=180
target5.x=170
target5.y=130
target6.height=50
target6.name=BinaerzahlenPruefer
target6.showInterface=false
target6.type=ClassTarget
target6.width=180
target6.x=380
target6.y=130

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path=""/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER">
<attributes>
<attribute name="module" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/5"/>
<classpathentry kind="output" path="bin"/>
</classpath>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>tabellen-dfa</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View file

@ -0,0 +1,102 @@
/**
* Implementiert einen DEA, der 0/1-Folgen darauf prüft, ob
* sie "gültige Binärzahlen" darstellen.
* Gültige Binärzahlen im Sinne dieser Aufgabe beginnen mit
* einer 1, auf die eine beliebige Folge von 0/1 folgt. Die
* einzelne Ziffer 0 ist ebenfalls erlaubt, jedoch keine
* Binärzahlen mit "überflüssigen" führenden Nullen. Die
* Binärzahl darf außerdem ein Vorzeichen führen (muss aber
* nicht).
*
* Gültig sind beispielsweise:
* 1
* 0
* 101
* 11
* 10
* 1110010010
* 111
* -1
* 1000000000
* +1
* 1001001100
*
* Ungültig sind beispielsweise:
* 123
* 00
* hallo
* 0000000011111
* 1+1
* Binärzahl
* abc
* 321
* 01010101010101
* 0101
* 01
* 0101010101
*
* @author Urs Lautebach
* @version 2021-Januar
*/
public class BinaerzahlenPruefer extends EndlicherAutomat {
/* Bei der Implementierung dieser Klasse muss man nur
* die Attribute alphabet, uebergaenge und endzustaende
* geeignet festlegen -- alles andere macht die
* Vaterklasse "EndlicherAutomat.java".
*
* Dort ist auch erklärt, wie die Nummerierung der
* Zustände, des Startzustand und der Übergangstabelle
* zu verstehen sind.
*/
// Transitionstabelle anlegen mit den Zuständen auf der
// senkrechten und den Alphabetzeichen auf der Rechtsachse:
private static final int[][] transiTabelle = new int [][] {
};
// Alphabet für diesen Automaten als char[]
private static final char[] binaerzAlph = new char[] {
};
// Menge der Endzustände:
private static final int[] endzustaende = new int[] {
};
/**
* Konstruktor für einen BinaerzahlenPruefer:
*/
public BinaerzahlenPruefer() {
// Aufruf des super-Konstruktors:
super(binaerzAlph, transiTabelle, endzustaende);
}
/**
* Die main-Methode erlaubt den Aufruf von
* Binaerzahlenpruefer von der Kommandozeile aus mit
* mehreren zu testenden Strings:
*
* java BinaerzahlenPruefer 1110101 0001 +1010 abc
*
* Die Ausgabe lautet dann
* Akzeptiert: "1110101" ist ein gueltiges Binärwort.
* FEHLER! "0001" ist kein gültiges Binärwort!
* Akzeptiert: "+1010" ist ein gueltiges Binärwort.
* FEHLER! "abc" ist kein gültiges Binärwort!
*/
public static void main(String[] args) {
// Endlichen Automaten instanziieren:
EndlicherAutomat binaerzahlenDFA = new BinaerzahlenPruefer();
for(String wort : args) {
if(binaerzahlenDFA.gehoertZuSprache(wort)) {
System.out.println("Akzeptiert: \"" + wort +
"\" ist ein gültiges Binärwort.");
} else {
System.out.println("FEHLER! \"" + wort +
"\" ist kein gültiges Binärwort!");
}
}
}
}

View file

@ -0,0 +1,104 @@
import static org.junit.Assert.*;
import org.junit.Test;
public class DEA_BeispieleTest {
public DEA_BeispieleTest() {
}
@Test
public void testBinaerzahlenPruefer() {
BinaerzahlenPruefer binZPruefer = new BinaerzahlenPruefer();
assertTrue(binZPruefer.gehoertZuSprache("1"));
assertTrue(binZPruefer.gehoertZuSprache("0"));
assertTrue(binZPruefer.gehoertZuSprache("+1"));
assertTrue(binZPruefer.gehoertZuSprache("+0"));
assertTrue(binZPruefer.gehoertZuSprache("-1"));
assertTrue(binZPruefer.gehoertZuSprache("-0"));
assertTrue(binZPruefer.gehoertZuSprache("11"));
assertTrue(binZPruefer.gehoertZuSprache("10"));
assertTrue(binZPruefer.gehoertZuSprache("+11"));
assertTrue(binZPruefer.gehoertZuSprache("-11"));
assertTrue(binZPruefer.gehoertZuSprache("+10"));
assertTrue(binZPruefer.gehoertZuSprache("1111"));
assertTrue(binZPruefer.gehoertZuSprache("1000"));
assertTrue(binZPruefer.gehoertZuSprache("10100101010111000"));
assertTrue(binZPruefer.gehoertZuSprache("1111111"));
assertFalse(binZPruefer.gehoertZuSprache(""));
assertFalse(binZPruefer.gehoertZuSprache("+"));
assertFalse(binZPruefer.gehoertZuSprache("-"));
assertFalse(binZPruefer.gehoertZuSprache("x"));
assertFalse(binZPruefer.gehoertZuSprache("binärzahl"));
assertFalse(binZPruefer.gehoertZuSprache("00"));
assertFalse(binZPruefer.gehoertZuSprache("+00"));
assertFalse(binZPruefer.gehoertZuSprache("0+0"));
assertFalse(binZPruefer.gehoertZuSprache("123"));
assertFalse(binZPruefer.gehoertZuSprache("0011"));
assertFalse(binZPruefer.gehoertZuSprache("011"));
assertFalse(binZPruefer.gehoertZuSprache("111111+"));
assertFalse(binZPruefer.gehoertZuSprache("000000+"));
assertFalse(binZPruefer.gehoertZuSprache("1+1"));
assertFalse(binZPruefer.gehoertZuSprache("0+1"));
assertFalse(binZPruefer.gehoertZuSprache("1+0"));
}
@Test
public void testMailadressenChecker() {
MailadressenChecker mailAdrPruefer = new MailadressenChecker();
assertTrue(mailAdrPruefer.gehoertZuSprache("b@b.bb"));
assertTrue(mailAdrPruefer.gehoertZuSprache("b@b.bbbb"));
assertTrue(mailAdrPruefer.gehoertZuSprache("b.b.b@bbb.bbb"));
assertTrue(mailAdrPruefer.gehoertZuSprache("bbbbbb@b.bb"));
assertTrue(mailAdrPruefer.gehoertZuSprache("b@b.b.b.b.bb"));
assertTrue(mailAdrPruefer.gehoertZuSprache("...@b.bb"));
assertTrue(mailAdrPruefer.gehoertZuSprache("...bbb@bb.bb"));
assertTrue(mailAdrPruefer.gehoertZuSprache("bbb...@bb.bb"));
assertFalse(mailAdrPruefer.gehoertZuSprache(""));
assertFalse(mailAdrPruefer.gehoertZuSprache("."));
assertFalse(mailAdrPruefer.gehoertZuSprache("b"));
assertFalse(mailAdrPruefer.gehoertZuSprache("@"));
assertFalse(mailAdrPruefer.gehoertZuSprache("bb@"));
assertFalse(mailAdrPruefer.gehoertZuSprache("b@b.b@bbb"));
assertFalse(mailAdrPruefer.gehoertZuSprache("@bb"));
assertFalse(mailAdrPruefer.gehoertZuSprache("bb@."));
assertFalse(mailAdrPruefer.gehoertZuSprache("bb@.."));
assertFalse(mailAdrPruefer.gehoertZuSprache("bb@bb.b"));
assertFalse(mailAdrPruefer.gehoertZuSprache("bb@bb.bb.b"));
assertFalse(mailAdrPruefer.gehoertZuSprache("bbb@bbb"));
assertFalse(mailAdrPruefer.gehoertZuSprache("bb.bb.bb.bb"));
assertFalse(mailAdrPruefer.gehoertZuSprache(
"bbb@bb.bb.bb@bb.bb"));
assertFalse(mailAdrPruefer.gehoertZuSprache("bbb@bbb..bbb"));
assertFalse(mailAdrPruefer.gehoertZuSprache("bbb@bbb.bbb.."));
}
@Test
public void test007Sucher() {
KGB_007Sucher detektiv = new KGB_007Sucher();
assertTrue(detektiv.gehoertZuSprache("007"));
assertTrue(detektiv.gehoertZuSprache("1007"));
assertTrue(detektiv.gehoertZuSprache("0071"));
assertTrue(detektiv.gehoertZuSprache("007007"));
assertTrue(detektiv.gehoertZuSprache("00007"));
assertTrue(detektiv.gehoertZuSprache("0000712"));
assertTrue(detektiv.gehoertZuSprache("2121200777"));
assertTrue(detektiv.gehoertZuSprache("0077"));
assertTrue(detektiv.gehoertZuSprache("212121007000000"));
assertTrue(detektiv.gehoertZuSprache("00712772712717"));
assertFalse(detektiv.gehoertZuSprache(""));
assertFalse(detektiv.gehoertZuSprache("0"));
assertFalse(detektiv.gehoertZuSprache("1"));
assertFalse(detektiv.gehoertZuSprache("2"));
assertFalse(detektiv.gehoertZuSprache("7"));
assertFalse(detektiv.gehoertZuSprache("07"));
assertFalse(detektiv.gehoertZuSprache("001"));
assertFalse(detektiv.gehoertZuSprache("002"));
assertFalse(detektiv.gehoertZuSprache("000"));
assertFalse(detektiv.gehoertZuSprache("001002"));
assertFalse(detektiv.gehoertZuSprache("7001"));
assertFalse(detektiv.gehoertZuSprache("0707"));
}
}

View file

@ -0,0 +1,167 @@
/**
* Implementiert einen tabellengetriebenen endlichen Automaten.
* Instanzen dieser Klasse sind DEAs, die Wörter über einem
* vorgegebenen Alphabet akzeptieren oder ablehnen können.
*
* Die Aufgabe wurde vom schriftlichen Abitur 2020 in
* Baden-Württemberg inspiriert.
*
* @author Urs Lautebach
* @version 2020-Oktober
*/
public class EndlicherAutomat {
private int [][] uebergaenge = null;
private int[] endzustaende = null;
private char[] alphabet = null;
/**
* Konstruiert einen tabellengetriebenen DEA. Nach dem
* erfolgreichen Aufruf dieses Konstruktors kann man den DEA
* anschließend durch einen Aufruf der Methode
* gehoertZuSprache(String):boolean
* beliebig viele Wörter testen lassen.
*
* @param tabelle Transitionstabelle des DEA. Die erste
* Dimension bezeichnet die Zustände; die zweite Dimension die
* Eingabezeichen. Die Einträge der Tabelle bezeichnen jeweils
* den Zustand, in den der Automat (abhängig vom vorherigen
* Zustand und der Eingabe) wechseln soll.
*
* Der Zustand 0 gilt als Fehlerzustand. Zustand 1 ist immer
* Startzustand (so dass der Startzustand, anders als bei der
* formalen Beschreibung eines DEA, nicht explizit angegeben
* werden muss).
*
* @param finalStates Ein int[], das die Endzustände enthält.
*
* @param alphabet ein Array von char, das das Alphabet des
* Automaten enthält. Die Reihenfolge der Zeichen im Alphabet
* muss der Reihenfolge der Zeichen an der entsprechenden
* Achse der Transitionstabelle entsprechen.
*/
EndlicherAutomat(final char[] alphabet,
final int[][] uebergaenge, final int[] endzustaende ) {
// Die Methode plausibilitaetPruefen ist fertig vorgegeben;
// sie fängt einige offensichtliche Fehler ab:
plausibilitaetPruefen();
}
/**
* Die Methode prüft, ob die Attribute transitionstabelle,
* alphabet und endzustaende zueinander passen. Sie ist fertig
* implementiert und dafür gedacht, am Ende des Konstruktors
* aufgerufen zu werden.
*/
private void plausibilitaetPruefen() {
if (uebergaenge == null) {
throw new IllegalArgumentException(
"Die Übergangstabelle ist null oder leer!");
}
if (alphabet == null) {
throw new IllegalArgumentException(
"Das Alphabet ist null oder leer!");
}
if (endzustaende == null) {
throw new IllegalArgumentException(
"endzustaende ist null oder leer!");
}
int tabelleHoehe = this.uebergaenge.length;
int tabelleBreite = uebergaenge[0].length;
// Hat die Übergangstabelle eine Zeile pro Alphabetzeichen?
if (tabelleBreite != alphabet.length) {
throw new IllegalArgumentException("Das Alphabet hat " +
alphabet.length + " Zeichen, die " +
" Übergangstabelle aber " + tabelleBreite +
" Spalten!");
}
// Sind alle Zeilen der Transitionstabelle gleich lang?
for (int[] zeile : uebergaenge) {
if (zeile.length != tabelleBreite) {
throw new IllegalArgumentException(
"Übergangstabelle ist nicht rechteckig!");
}
}
// Hat einer der Endzustände eine unplausible Nummer?
for (int zustand : endzustaende) {
if (zustand < 1 || zustand > tabelleHoehe - 1) {
throw new IllegalArgumentException(
"Der Endzustand " + zustand +
" kommt in der Übergangstabelle nicht vor!");
}
}
}
/**
* Ermittelt die Nummer (den Index) des angegebenen Zeichens
* innerhalb des Alphabetes dieses Automaten.
*
* @param input Zeichen, dessen Position ermittelt werden soll.
* @returns Position des Zeichens input innerhalb des Alphabets
* dieses Automaten; oder -1, falls es im Alphabet nicht
* enthalten ist.
*/
public int indexImAlphabet(char input) {
// TODO: Implementieren Sie diese Methode.
/* Man geht das Alphabet durch und prüft, welches seiner
* Zeichen dem "input" entspricht. Falls man es findet,
* gibt man dessen Index zurück.
*/
return -54321; // dummy return
}
/**
* Überprüft, ob der Zustand mit der übergebenen
* Zustandsnummer einer der Endzustände dieses Automaten ist.
*
* @param nr Nummer des fraglichen Zustandes.
* @return ob der Zustand ein Endzustand ist.
*/
public boolean istEndzustand(int nr) {
// TODO: Implementieren Sie diese Methode.
return false; // dummy return
}
/**
* Die Methode kann mit einem String als Parameter aufgerufen
* werden, was oft bequemer ist als ein char[].
*
* @param s String mit dem zu prüfenden Wort.
* @return ob s von diesem Automaten erkannt wird.
*/
public boolean gehoertZuSprache(String s) {
// Hier ist nichts zu implementieren.
return gehoertZuSprache(s.toCharArray());
}
/**
* Übergibt dem DEA ein ganzes Wort und ermittelt, ob er es
* akzeptiert oder nicht.
*
* @param eingabe Die komplette zu analysierende Eingabe als
* char[].
* @returns true, wenn das Wort vom DEA akzeptiert wird;
* false sonst.
*/
public boolean gehoertZuSprache(final char[] wort) {
// TODO: Implementieren Sie diese Methode.
/*
* Um zu prüfen, ob wort akzeptiert wird, muss der DEA...
*
* - in Zustand 1 beginnen;
*
* - das Eingabewort Zeichen für Zeichen durchgehen;
*
* - prüfen, ob das Zeichen im Alphabet vorkommt;
*
* - nach dessen Position im Alphabet und altem Zustand
* einen neuen Zustand aus der Tabelle uebergaenge wählen;
*
* - false antworten, wenn er im Fehlerzustand landet,
*
* - am Schluss der Eingabe entscheiden, ob der erreichte
* Zustand ein Endzustand ist.
*/
return false; // dummy return
}
}

View file

@ -0,0 +1,85 @@
/**
* Dieser DFA erkennt Ziffernfolgen, in denen sich irgendwo
* James Bond versteckt hat -- in denen also die Folge 007
* vorkommt.
*
* Die folgenden Ziffernfolgen sollen beispielsweise akzeptiert
* werden:
*
* 12107117700710012021,
* 007,
* 0071121727,
* 0000000071121727,
* 007007007007,
* 1121271201212007.
*
* Die folgenden Ziffernfolgen sollen nicht akzeptiert werden:
*
* 12107110710012021,
* 07,
* 00,
* 07112172,
* 1121271201212000.
* Um den Automaten und vor allem die Übergangstabelle
* übersichtlicher zu halten, verwendet er nicht alle Ziffern,
* sondern lediglich das eingeschränkte Alphabet {0, 1, 2, 7}.
*
* Es empfiehlt sich, den Automaten zunächst zu zeichnen,
* die Übergangstabelle auf Papier zu erstellen und dann zu
* programmieren.
*
* @author Urs Lautebach
* @version 2020-Okt
*/
public class KGB_007Sucher extends EndlicherAutomat {
/* Bei der Implementierung dieser Klasse muss man nur
* die Attribute alphabet, uebergaenge und endzustaende
* geeignet festlegen -- alles andere macht die
* Vaterklasse.
*/
private static final char[] alphabet = new char[] {
};
private static final int[][] uebergaenge = new int[][] {
};
private static final int[] endzustaende = new int[] {
};
/**
* Instanziiert einen KGB_007Sucher-DFA.
*/
KGB_007Sucher() {
// Aufruf des super-Konstruktors:
super(alphabet, uebergaenge, endzustaende);
}
/**
* Die main-Methode erlaubt den Aufruf des
* Binaerzahlenpruefers von der Kommandozeile aus mit:
*
* java KGB_007Sucher 127007117 1717771021
*
* Die Ausgabe lautet dann
*
* Akzeptiert: "127007117" enthält 007.
* FEHLER! "1717771021" enthält kein 007!
*/
public static void main(String[] args) {
// Endlichen Automaten instanziieren:
EndlicherAutomat fahnder = new KGB_007Sucher();
for(String wort : args) {
if(fahnder.gehoertZuSprache(wort)) {
System.out.println("Akzeptiert: \"" + wort +
"\" enthält 007.");
} else {
System.out.println("FEHLER! \"" + wort +
"\" enthält kein 007!");
}
}
}
}

View file

@ -0,0 +1,83 @@
/**
* Die Klasse implementiert einen DEA für die Überprüfung äußerst
* einfacher Mailadressen, die nur aus dem Buchstaben b, Punkten
* und dem at-Zeichen bestehen dürfen. Der Nutzername darf fast
* beliebig aufgebaut sein; die Domain muss mindestens zweistufig
* sein und die Toplevel-Domain muss mindestens zwei Zeichen haben.
*
* Gültig sind damit beispielsweise:
* b@b.bb
* b@b.bbbb
* b.b.b@bbb.bbb
* bbbbbb@b.bb
* b@b.b.b.b.bb
* ...@b.bb
* ...bbb@bb.bb
* bbb...@bb.bb
*
* Ungültig sind beispielsweise:
* .
* b
* @
* bb@
* b@b.b@bbb
* b@b.b@bb.b
* @bb
* bb@.
* bb@..
*
* Tatsächlich ist die Überprüfung realer Mailadressen wesentlich
* komlizierter als in diesem Beispiel.
*
* @author Urs Lautebach
* @version 2021-Janar
*
*/
public class MailadressenChecker extends EndlicherAutomat {
/* Bei der Implementierung dieser Klasse muss man nur
* die Attribute alphabet, uebergaenge und endzustaende
* geeignet festlegen -- alles andere macht die
* Vaterklasse.
*/
private static final char[] alphabet = new char[] {
};
private static final int[][] transitionen = new int[][] {
};
private static final int[] endzustaende = new int[] {
};
MailadressenChecker() {
// Aufruf des super-Konstruktors:
super(alphabet, transitionen, endzustaende);
}
/**
* Die main-Methode erlaubt den Aufruf des
* Binaerzahlenpruefers von der Kommandozeile mit beliebig
* vielen zu prüfenden Strings:
* java MailadressenChecker bbb.b@bb.bb a@b@c
*
* Die Ausgabe lautet dann
*
* Akzeptiert: "bbb.b@bb.bb" ist eine gültige Mailadresse.
* FEHLER! "a@b@c" ist als Mailadresse ungültig!
*/
public static void main(String[] args) {
// Endlichen Automaten instanziieren:
EndlicherAutomat checker = new MailadressenChecker();
for(String wort : args) {
if(checker.gehoertZuSprache(wort)) {
System.out.println("Akzeptiert: \"" + wort +
"\" ist eine gültige Mailadresse.");
} else {
System.out.println("FEHLER! \"" + wort +
"\" ist als Mailadresse ungültig!");
} // end if
} // end for
} // end main
} // end class

View file

@ -0,0 +1,3 @@
# Tabellen Dfa
Implementierung eines allgemeinen tabellengetriebenen DFA als Programmieraufgabe (samt einiger Beispiel-DFA).

View file

@ -0,0 +1,36 @@
Dieser Ordner enthält ein Java-Projekt, in dem die Implementierung
eines tabellengetriebenen DEA geübt wird. Es kann mit BlueJ oder
einem anderen Java-Werkzeug bearbeitet werden.
Das Projekt liegt in drei Ausstattungen vor; Sie als Lehrkraft
entscheiden, welche Variante(n) Sie den Schülern vorlegen.
Der Ordner...
.skelett
--------
enthält das Rohprojekt ohne Lösungshinweise oder Tipps, aber mit
Spezifikation, Arbeitsanweisungen und JUnit-Test. Das Projekt
sollte fehlerfrei compilieren und lauffähig sein, aber natürlich
schlagen die Tests fehl.
.tipp
-----
enthält das gleiche Projekt, aber zusätzlich mit Tipps für die
Bearbeitung durch Schüler.
.lsg
----
enthält die Musterlösung des fertig ausprogrammierten Projekts.
Hier sollten alle Tests erfolgreich laufen.
Zu bearbeiten sind die Datei EndlicherAutomat.java, in der der
eigentliche Tabellenmechanismus implementiert wird, und eine Auswahl
der Beispiel-DFA für
Mailadressen
007-Suche
oder Binärzahlen
bzw. eigene DFA für andere Sprachen nach Wahl.

View file

@ -0,0 +1,75 @@
#BlueJ package file
dependency1.from=DFA_BeispieleTest
dependency1.to=BinaerzahlenPruefer
dependency1.type=UsesDependency
dependency2.from=DFA_BeispieleTest
dependency2.to=MailadressenChecker
dependency2.type=UsesDependency
dependency3.from=DFA_BeispieleTest
dependency3.to=KGB_007Sucher
dependency3.type=UsesDependency
editor.fx.0.height=0
editor.fx.0.width=0
editor.fx.0.x=0
editor.fx.0.y=0
objectbench.height=119
objectbench.width=770
package.divider.horizontal=0.5785785785785785
package.divider.vertical=0.7519685039370079
package.editor.height=375
package.editor.width=643
package.editor.x=100
package.editor.y=100
package.frame.height=600
package.frame.width=800
package.numDependencies=3
package.numTargets=6
package.showExtends=true
package.showUses=true
project.charset=UTF-8
readme.height=58
readme.name=@README
readme.width=47
readme.x=10
readme.y=10
target1.height=62
target1.name=bin
target1.type=PackageTarget
target1.width=80
target1.x=70
target1.y=10
target2.height=50
target2.name=KGB_007Sucher
target2.showInterface=false
target2.type=ClassTarget
target2.width=140
target2.x=10
target2.y=130
target3.height=50
target3.name=DFA_BeispieleTest
target3.showInterface=false
target3.type=UnitTestTargetJunit4
target3.width=160
target3.x=180
target3.y=240
target4.height=50
target4.name=EndlicherAutomat
target4.showInterface=false
target4.type=ClassTarget
target4.width=160
target4.x=180
target4.y=30
target5.height=50
target5.name=MailadressenChecker
target5.showInterface=false
target5.type=ClassTarget
target5.width=180
target5.x=170
target5.y=130
target6.height=50
target6.name=BinaerzahlenPruefer
target6.showInterface=false
target6.type=ClassTarget
target6.width=180
target6.x=380
target6.y=130