Subtrees hinzugefügt
This commit is contained in:
parent
0a64a479b0
commit
29d4112506
42 changed files with 2889 additions and 0 deletions
7
Quellcodes/AuS_A_DFA_Implementieren/.gitignore
vendored
Normal file
7
Quellcodes/AuS_A_DFA_Implementieren/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
**/*.sh
|
||||
**/*.class
|
||||
**/*.ctxt
|
||||
repo.adoc
|
||||
repo_subtree.adoc
|
||||
/alt
|
||||
/hide
|
||||
11
Quellcodes/AuS_A_DFA_Implementieren/lehrer/.classpath
Normal file
11
Quellcodes/AuS_A_DFA_Implementieren/lehrer/.classpath
Normal 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>
|
||||
17
Quellcodes/AuS_A_DFA_Implementieren/lehrer/.project
Normal file
17
Quellcodes/AuS_A_DFA_Implementieren/lehrer/.project
Normal 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>
|
||||
|
|
@ -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!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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"));
|
||||
}
|
||||
}
|
||||
|
||||
212
Quellcodes/AuS_A_DFA_Implementieren/lehrer/EndlicherAutomat.java
Normal file
212
Quellcodes/AuS_A_DFA_Implementieren/lehrer/EndlicherAutomat.java
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
106
Quellcodes/AuS_A_DFA_Implementieren/lehrer/KGB_007Sucher.java
Normal file
106
Quellcodes/AuS_A_DFA_Implementieren/lehrer/KGB_007Sucher.java
Normal 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!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
3
Quellcodes/AuS_A_DFA_Implementieren/lehrer/README.md
Normal file
3
Quellcodes/AuS_A_DFA_Implementieren/lehrer/README.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# Tabellen Dfa
|
||||
|
||||
Implementierung eines allgemeinen tabellengetriebenen DFA als Programmieraufgabe (samt einiger Beispiel-DFA).
|
||||
|
|
@ -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.
|
||||
|
||||
75
Quellcodes/AuS_A_DFA_Implementieren/lehrer/package.bluej
Normal file
75
Quellcodes/AuS_A_DFA_Implementieren/lehrer/package.bluej
Normal 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
|
||||
11
Quellcodes/AuS_A_DFA_Implementieren/lsg/.classpath
Normal file
11
Quellcodes/AuS_A_DFA_Implementieren/lsg/.classpath
Normal 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>
|
||||
17
Quellcodes/AuS_A_DFA_Implementieren/lsg/.project
Normal file
17
Quellcodes/AuS_A_DFA_Implementieren/lsg/.project
Normal 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>
|
||||
113
Quellcodes/AuS_A_DFA_Implementieren/lsg/BinaerzahlenPruefer.java
Normal file
113
Quellcodes/AuS_A_DFA_Implementieren/lsg/BinaerzahlenPruefer.java
Normal 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!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
104
Quellcodes/AuS_A_DFA_Implementieren/lsg/DEA_BeispieleTest.java
Normal file
104
Quellcodes/AuS_A_DFA_Implementieren/lsg/DEA_BeispieleTest.java
Normal 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"));
|
||||
}
|
||||
}
|
||||
|
||||
196
Quellcodes/AuS_A_DFA_Implementieren/lsg/EndlicherAutomat.java
Normal file
196
Quellcodes/AuS_A_DFA_Implementieren/lsg/EndlicherAutomat.java
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
92
Quellcodes/AuS_A_DFA_Implementieren/lsg/KGB_007Sucher.java
Normal file
92
Quellcodes/AuS_A_DFA_Implementieren/lsg/KGB_007Sucher.java
Normal 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!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
3
Quellcodes/AuS_A_DFA_Implementieren/lsg/README.md
Normal file
3
Quellcodes/AuS_A_DFA_Implementieren/lsg/README.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# Tabellen Dfa
|
||||
|
||||
Implementierung eines allgemeinen tabellengetriebenen DFA als Programmieraufgabe (samt einiger Beispiel-DFA).
|
||||
|
|
@ -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.
|
||||
|
||||
75
Quellcodes/AuS_A_DFA_Implementieren/lsg/package.bluej
Normal file
75
Quellcodes/AuS_A_DFA_Implementieren/lsg/package.bluej
Normal 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
|
||||
11
Quellcodes/AuS_A_DFA_Implementieren/readme.adoc
Normal file
11
Quellcodes/AuS_A_DFA_Implementieren/readme.adoc
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
= Material :
|
||||
|
||||
|===
|
||||
|Zuordnung|
|
||||
|Klassenstufe|
|
||||
|Bildungsplanbezug |
|
||||
|Werkzeug|
|
||||
|Autoren|
|
||||
|===
|
||||
|
||||
== Inhalt
|
||||
11
Quellcodes/AuS_A_DFA_Implementieren/roh/.classpath
Normal file
11
Quellcodes/AuS_A_DFA_Implementieren/roh/.classpath
Normal 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>
|
||||
17
Quellcodes/AuS_A_DFA_Implementieren/roh/.project
Normal file
17
Quellcodes/AuS_A_DFA_Implementieren/roh/.project
Normal 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>
|
||||
|
|
@ -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!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
104
Quellcodes/AuS_A_DFA_Implementieren/roh/DEA_BeispieleTest.java
Normal file
104
Quellcodes/AuS_A_DFA_Implementieren/roh/DEA_BeispieleTest.java
Normal 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"));
|
||||
}
|
||||
}
|
||||
|
||||
146
Quellcodes/AuS_A_DFA_Implementieren/roh/EndlicherAutomat.java
Normal file
146
Quellcodes/AuS_A_DFA_Implementieren/roh/EndlicherAutomat.java
Normal 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
|
||||
}
|
||||
}
|
||||
|
||||
80
Quellcodes/AuS_A_DFA_Implementieren/roh/KGB_007Sucher.java
Normal file
80
Quellcodes/AuS_A_DFA_Implementieren/roh/KGB_007Sucher.java
Normal 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!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
3
Quellcodes/AuS_A_DFA_Implementieren/roh/README.md
Normal file
3
Quellcodes/AuS_A_DFA_Implementieren/roh/README.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# Tabellen Dfa
|
||||
|
||||
Implementierung eines allgemeinen tabellengetriebenen DFA als Programmieraufgabe (samt einiger Beispiel-DFA).
|
||||
|
|
@ -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.
|
||||
|
||||
75
Quellcodes/AuS_A_DFA_Implementieren/roh/package.bluej
Normal file
75
Quellcodes/AuS_A_DFA_Implementieren/roh/package.bluej
Normal 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
|
||||
11
Quellcodes/AuS_A_DFA_Implementieren/tipp/.classpath
Normal file
11
Quellcodes/AuS_A_DFA_Implementieren/tipp/.classpath
Normal 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>
|
||||
17
Quellcodes/AuS_A_DFA_Implementieren/tipp/.project
Normal file
17
Quellcodes/AuS_A_DFA_Implementieren/tipp/.project
Normal 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>
|
||||
|
|
@ -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!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
104
Quellcodes/AuS_A_DFA_Implementieren/tipp/DEA_BeispieleTest.java
Normal file
104
Quellcodes/AuS_A_DFA_Implementieren/tipp/DEA_BeispieleTest.java
Normal 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"));
|
||||
}
|
||||
}
|
||||
|
||||
167
Quellcodes/AuS_A_DFA_Implementieren/tipp/EndlicherAutomat.java
Normal file
167
Quellcodes/AuS_A_DFA_Implementieren/tipp/EndlicherAutomat.java
Normal 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
|
||||
}
|
||||
}
|
||||
|
||||
85
Quellcodes/AuS_A_DFA_Implementieren/tipp/KGB_007Sucher.java
Normal file
85
Quellcodes/AuS_A_DFA_Implementieren/tipp/KGB_007Sucher.java
Normal 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!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
3
Quellcodes/AuS_A_DFA_Implementieren/tipp/README.md
Normal file
3
Quellcodes/AuS_A_DFA_Implementieren/tipp/README.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# Tabellen Dfa
|
||||
|
||||
Implementierung eines allgemeinen tabellengetriebenen DFA als Programmieraufgabe (samt einiger Beispiel-DFA).
|
||||
|
|
@ -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.
|
||||
|
||||
75
Quellcodes/AuS_A_DFA_Implementieren/tipp/package.bluej
Normal file
75
Quellcodes/AuS_A_DFA_Implementieren/tipp/package.bluej
Normal 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
|
||||
Loading…
Add table
Add a link
Reference in a new issue