Datum:
Hallo, ich habe die Aufgabe einen Syntaxchecker in Java zu programmieren, der einen vorgegebenen J.Unit test erfolgreich absolviert. Die Methode public static void parse(String kd) throws ParseException ist vorgegeben, die restlichen Methoden habe ich bereits programmiert. Ich versuche also rekursiv den Syntaxbaum zu überprüfen, jedoch erfüllt es mir keinen J-Unit Test:
package u3a3;
public class KD {
private static int offset = 0;
/**
* Parse a "Klammerdarstellung" (KD) of a tree.
*
* <ul>
* <li>An empty tree is encoded as '-'.</li>
* <li>A node is encoded as an uppercase letter, i.e. everything accepted by {@link Character#isUpperCase(char)}.</li>
* <li>Children are appended to the father as a ','-separated list of nodes enclosed in round brackets.</li>
* </ul>
*
* @param kd Tree encoded in KD
* @throws ParseException if the given String is not a valid KD of a tree.
*/
public static void parse(String kd) throws ParseException
{
if (kd.length() > 1 && kd.charAt(0) != '-' && kd.charAt(1) != '-')
{
tree(kd,0);
}
}
public static int tree(String str, int offset)
{
offset = follower(str, offset);
while (str.length() > offset && str.charAt(offset) == '+'){
offset = follower(str, offset + 1);
}
return offset;
}
public static int follower(String str, int offset)
{
offset = node(str, offset);
while (str.length() > offset && str.charAt(offset) == '*'){
offset = node(str, offset + 1);
}
return offset;
}
public static int node(String str, int offset)
{
while (str.length() > offset && str.charAt(offset) == '(' || str.charAt(offset) == ')'){
offset = node(str, offset + 1);
}
return offset;
}
}
|
Hier noch der JUnit test:
package u3a3;
import org.junit.Test;
public class Tests {
void testCase(String lkd) throws ParseException {
KD.parse(lkd);
}
@Test public void empyTree() throws ParseException { testCase("-"); }
@Test public void onlyRoot() throws ParseException { testCase("A"); }
@Test public void balancedTree() throws ParseException { testCase("A(B,C)"); }
@Test public void listLeft() throws ParseException { testCase("A(B(C,-),-)"); }
@Test public void listLeftImplicit() throws ParseException { testCase("A(B(C))"); }
@Test public void listRight() throws ParseException { testCase("A(-,B(-,C))"); }
@Test public void missingSibling() throws ParseException { testCase("A(B,-,C)");}
@Test public void noChildren() throws ParseException { testCase("A(-,-)");}
@Test public void genericTree() throws ParseException { testCase("A(-,B(C),-,D(E(-,F(G,H)),I))"); }
@Test(expected = ParseException.class)
public void empyString() throws ParseException { testCase(""); }
@Test(expected = ParseException.class)
public void noChild()throws ParseException { testCase("A()"); }
@Test(expected = ParseException.class)
public void noSibling()throws ParseException { testCase("A(B,)"); }
@Test(expected = ParseException.class)
public void twoCommas()throws ParseException { testCase("A(B,,C)"); }
@Test(expected = ParseException.class)
public void missingOpenBrace()throws ParseException { testCase("AB)"); }
@Test(expected = ParseException.class)
public void missingCloseBrace()throws ParseException { testCase("A(B"); }
@Test(expected = ParseException.class)
public void missingComma()throws ParseException { testCase("A(BC)"); }
@Test(expected = ParseException.class)
public void garbage()throws ParseException { testCase("A(B)C"); }
@Test(expected = ParseException.class)
public void garbage2()throws ParseException { testCase("A(B)(C)"); }
@Test(expected = ParseException.class)
public void noRoot()throws ParseException { testCase("-(A)"); }
@Test(expected = ParseException.class)
public void invalidNode()throws ParseException { testCase("A(1)"); }
}
|
Vielleicht sieht jemand was ich falsch mache. mfg Hans
Datum:
Was sagt der Debugger? Du kannst jeden Test Step für Step durchgehen und genau sehen was passiert.
Datum:
Ok, danke, gleich mal probieren
Datum:
Da du niergends eine Parseexception wirfst, der Test aber eine erwartet schlägt er fehl. Was würdest du auch von einem Compiler halten welcher Kommentarlos jeden Unsinn aktzeptiert und keine Ausgaben macht egal ob richtig oder falsch?
Datum:
@Läubi
ich glaub nicht, dass das stimmt, was du schreibst
throws heitß ja nur dass man eine Parseexception werfen KÖNNTE
und nicht dass man das MUSS
(wird man vermutlich nur tun, wenn man das scheitern eines tests
kommunizieren will
>von einem Compiler
ich glaub nicht, dass er ein Problem beim compilieren hat ...
@TO
class Tests {
fehlt da ein "extends" ??
Datum:
Habe nun einmal die erste methode überarbeitet:
public static void parse(String kd) throws ParseException
{
boolean exception = false;
for (int i = 0; i<kd.length(); i++)
{
if (kd.charAt(i) == '(' || kd.charAt(i) == ')' || kd.charAt(i) == ',' || kd.charAt(i) == '-' || kd.charAt(i) >= 'A' && kd.charAt(i) <= 'Z')
{
} else {
exception = true;
i = kd.length();
}
}
if (exception == false)
{
tree (kd,0);
}
}
|
Jetzt sollte sie zumindest eine Ausnahme erkennen, wie bringe ich das nun in diese Junit Test mit ein?
Datum:
Ich begreiffe einfach diesen JUnit Test nicht, ich weiss gar nicht was ich überhaupt erfüllen soll? Was muss ich machen, dass es mir die Exceptions richtig erfüllt?
Datum:
Hi, wieso sollte eine Exception erkannt werden, wenn du exception = true; setzt? Vll. solltest du erst mal nachschlagen, was Exceptions sind und wozu sie verwendet werden. Anstelle von exception = true wirfst du einfach eine Exception wenn einer deiner Tests fehlgeschlagen ist: throw new ParseException(); Natürlich sollte die ParseException Informationen über die Fehlerquelle, Position etc. enthalten...
Datum:
Robert L. schrieb: > @Läubi > > ich glaub nicht, dass das stimmt, was du schreibst > throws heitß ja nur dass man eine Parseexception werfen KÖNNTE > und nicht dass man das MUSS Aber > @Test(expected = ParseException.class) > > ich glaub nicht, dass er ein Problem beim compilieren hat ... > > > @TO > > class Tests { > > fehlt da ein "extends" ?? extends TestCase wurde mit JUnit 4 abgeschafft. Du bist wohl noch bei JUnit 3?;-) Ich auch... mfg Andreas
Datum:
Robert L. schrieb: > ich glaub nicht, dass das stimmt Glauben heißt nicht wissen, der JUnittest erwartet das die Exception geworfen wird siehe weiter unten. Hans Lüthi schrieb: > Ich begreiffe einfach diesen JUnit Test nicht, ich weiss > gar nicht was ich überhaupt erfüllen soll? Dann sprich mit deinem Betreuer! Hans Lüthi schrieb: > @Test(expected = ParseException.class) Das sagt aus, dass der Test erwartet, dass die Methode eine Exception vom Typ ParseException wirft. (siehe z.B. http://radio.javaranch.com/lasse/2007/05/17/117940...)
Datum:
Also, ich verstehe schon, dass die Ausnahmen als Exceptions geworfen werden sollen, mit "throw new ParseException();" klappt das aber nicht, zeigt mir Eclipse als Fehler an. Mit exceptions = true meine ich nur, dass es sich um eine Ausnahme handelt, somit versuche ich zu verhindern, dass es in den Syntaxchecker läuft. Wie aber werfe ich in Junit4 eine exception? Gruss Hans
Datum:
Hans Lüthi schrieb: > "throw new ParseException();" klappt das aber nicht, > zeigt mir Eclipse als Fehler an. und welchen?
Datum:
The constructor ParseException() is undefined, naja, sollte ich wohl noch einen Konstruktor machen, weiss aber nicht warum ich bei ParseException nen Konstruktor brauche? $ Edit: sehe gerade, der Konsturktor is in einer anderen Klasse definiert.
Datum:
Also du scheinst wohl noch ganz am Anfang zu sein;-)
Bei Eclipse kannst du mit F2 die Dokumentation anzeigen lassen, und mit
F3 in die Sourcen springen (sofern vorhanden).
ParseException ist nirgends importiert, daher wird es wohl eine Klasse
in der gleichen Package sein.
Ich vermute mal diese Klasse hat einen Konstruktor der z.B. einen String
als Parameter verlangt, warscheinlich einen Fehler.
(Alles geraten, wissen kannst das nur DU).
dann würde es heissen throw new ParserException("Mein Fehler");
Aja, ganz wichtig: Wenn du auf den Fehler klickst (also das rote Icon an
der Linke Seite) sagt dir Eclipse oft einen Lösungsvorschlag.
Schau den dir mal an!
Meistens geht der in die richtige Richtung.
mfg Andreas
Datum:
Danke, alles richtig geraten.
Datum:
So, habe das Programm mal so verändert:
package u3a3;
public class KD {
private static int offset = 0;
/**
* Parse a "Klammerdarstellung" (KD) of a tree.
*
* <ul>
* <li>An empty tree is encoded as '-'.</li>
* <li>A node is encoded as an uppercase letter, i.e. everything accepted by {@link Character#isUpperCase(char)}.</li>
* <li>Children are appended to the father as a ','-separated list of nodes enclosed in round brackets.</li>
* </ul>
*
* @param kd Tree encoded in KD
* @throws ParseException if the given String is not a valid KD of a tree.
*/
public static void parse(String kd) throws ParseException
{
boolean exception = false;
for (int i = 0; i<kd.length(); i++) //This for-loop show, if in the tree string has illegal characters
{
if ((kd.charAt(i) == '(' || kd.charAt(i) == ')' || kd.charAt(i) == ',' || kd.charAt(i) == '-' || ((int) kd.charAt(i) >= 65) && ((int) kd.charAt(i) <= 90)))
{
} else {
exception = true;
i = kd.length();
}
}
if (exception == false)
{
tree (kd,0);
} else if (exception == true) // if the string has illegal characters
{
throw new ParseException("",0);
}
}
public static int tree(String str, int offset)
{
offset = follower(str, offset);
while (str.length() > offset && (((int) str.charAt(offset) >= 65) && ((int) str.charAt(offset) <= 90 ))){
offset = follower(str, offset + 1);
}
return offset;
}
public static int follower(String str, int offset)
{
offset = node(str, offset);
while (str.length() > offset && str.charAt(offset) == '('){
offset = node(str, offset + 1);
}
return offset;
}
public static int node(String str, int offset)
{
while (str.length() > offset && (((int) str.charAt(offset) >= 65) && ((int) str.charAt(offset) <= 90 ))){
offset = node(str, offset + 1);
}
return offset;
}
}
|
10 Tests werden noch nicht erfüllt. Das offset soll zeigen, ob die Klammerdarstellung auch wirklich richtig ist. Vielleicht sieht jemand noch einen Fehler.
Datum:
Was sollen die ganze integer da? Und die Exeption kann man sofort werfen wenn etwas schief lief, außerdem solltest du dich mal einigen wo du die Klammer setzen willst oder einfach mit STRG+F mal den Source formatieren lassen. Außerdem wäre es ganz gut wenn du mal versuchst zu verstehen was da abläuft anstelle aus allen möglichen Quellen was zusammenzukopieren.
Datum:
Naja, das was da steht habe auch ich so gedacht und nicht einfach so zusammenkopiert. Ich konvertiere die Chars in einen Integer um damit zu sehen, ob es ein erlaubter Grossbuchstabe ist (Wert zwischen 64 und 91). Die Bäume die ich überprüfe sind aus Grossbuchstaben, Kommas, Klammern und "-" für keinen Baum.
Datum:
Läubi .. schrieb: > Klammer setzen willst oder einfach mit STRG+F mal den Source formatieren > lassen. STRG+SHIF+F, er will nicht suchen;-) Hans Lüthi schrieb: > Naja, das was da steht habe auch ich so gedacht und nicht einfach so > zusammenkopiert. Ich konvertiere die Chars in einen Integer um damit zu > sehen, ob es ein erlaubter Grossbuchstabe ist (Wert zwischen 64 und 91). Character.isLetter(ch) Character.isUpperCase(ch) Es gibt noch einige mehr, schaue die dir mal an. Im übrigen ist es leserlicher (und ggf. sogar etwas schneller) wenn du statt > if ((kd.charAt(i) == '(' || kd.charAt(i) == ')' || kd.charAt(i) == > ',' || kd.charAt(i) == '-' || ((int) kd.charAt(i) >= 65) && ((int) > kd.charAt(i) <= 90))) etwas schreibst wie > char c = kd.charAt(i); > if ((c == '(' || c == ')' || c == ',' || c == '-' || ((int) c >= > 65) && ((int) c <= 90))) mfg Andreas
Datum:
So, habe alles probiert, das ist dabei rausgekommen, funktioniert leider nicht ganz, vielleicht sieht jemand noch einen Fehler:
package u3a3;
public class KD {
private static int offset = 0;
/**
* Parse a "Klammerdarstellung" (KD) of a tree.
*
* <ul>
* <li>An empty tree is encoded as '-'.</li>
* <li>A node is encoded as an uppercase letter, i.e. everything accepted by
* {@link Character#isUpperCase(char)}.</li>
* <li>Children are appended to the father as a ','-separated list of nodes
* enclosed in round brackets.</li>
* </ul>
*
* @param kd
* Tree encoded in KD
* @throws ParseException
* if the given String is not a valid KD of a tree.
*/
public static void parse(String kd) throws ParseException {
boolean exception = false;
for (int i = 0; i < kd.length(); i++) // This for-loop show, if in the
// tree string has illegal
// characters
{
offset = i;
if ((kd.charAt(i) == '(' || kd.charAt(i) == ')'
|| kd.charAt(i) == ',' || kd.charAt(i) == '-' || Character
.isUpperCase(kd.charAt(i)))) {
} else {
exception = true;
i = kd.length();
}
}
if (exception == false && kd.length() > 0) {
offset = 0;
tree(kd, offset);
if (offset != kd.length())
{
throw new ParseException(kd, offset);
}
} else if (exception == true || kd.length() == 0) {
throw new ParseException(kd, offset);
}
}
public static int tree(String str, int offset) {
offset = node(str, offset);
if (str.length() > offset && (str.charAt(offset) == '(' )) {
offset = undertree(str, offset + 1);
} else if (str.charAt(offset) == ')')
{
offset = offset + 1;
}
return offset;
}
public static int node(String str, int offset) {
if (str.length() > offset && (Character.isUpperCase(str.charAt(offset)) || str.charAt(offset) == '-')) {
return (offset + 1);
} else {
return 0;
}
}
public static int undertree(String str, int offset) {
offset = tree(str,offset + 1);
while (str.length() > offset && str.charAt(offset) == ',') {
offset = node(str, offset + 1);
}
return offset;
}
}
|