Assignment 6, due Oct 6

Solutions

Part of the homework for CS:2820, Fall 2017
by Douglas W. Jones
THE UNIVERSITY OF IOWA Department of Computer Science

  1. Background: The code for class ScanSupport given at the end of the notes for Lecture 10 on Sept. 26 raises some questions: Consider writing a nextFloat method to add to ScanSupport. A preliminary version of this would be very similar to nextName except that the final two lines would be:
    sc.skip( number );
    return Float.parseFloat( sc.match().group() );
    

    a) ScanSupport has no tools equivalent to the hasNext methods of the scanner. If there is no next name on the current input line, what does nextName() return? (This has an impact on the pattern you use and it is the origin of an error in the above code.) (0.5 points)

    It returns an empty string.

    (That means that the pattern must match an empty string, and in the above code, this leads parseFloat to throw a NumberFormatException if there is no float on the input line.)

    b) Give a declaration for the pattern named number above that recognizes 10, 9.12, 87. and .6345 (for example), as well as handling the possibility that there is no floating point number before the end of line. (0.5 points)

    There are numerous equally good answers. Here is the one with a small intellectual footprint (that is, it avoids using obscure features of regular expressions):

    private static final Pattern number
        = Pattern.compile(
            "\\([0-9][0-9]*\\(|\\.[0-9]*\\)\\)|\\(\\.[0-9][0-9]*\\)|"
        );
    
    The overall structure of the declaration given above matches that from the code distributed on Sept. 26. The pattern matches either:
    • a number starting with at least one digit, followed optionally by a point followed by optional digits, or
    • a number starting with a point, followed by at least one digit, or
    • an empty string

    This question didn't ask for a leading - sign, but an optional leading minus could be added to the first two choices above by including \(|-\).

    Also note that the question did ask for a declaration, not just an informal regular expression. This means that you need to give the regular expression in Java's so you're n't specify the need to use Java's regular expression notation.

    All the backslashes in the string constant have been doubled because when the Java compiler reads a string, it takes backslash as a special character, a prefix on things like \n representing newline. If you want to include a backslash in the string, you have to write \\. This seriously messes up the readability of the code!

    c) Fix the code given above so that it returns Float.NaN if there is no next floating point number on the current input line. (That's a special float value that represents something that is not a number. If you have a float named f, f.isNaN() tests to see if the value is not a number.) (0.5 points)

    There are two fairly obvious solutions. One is to catch the exception:

    sc.skip( number );
    try {
        return Float.parseFloat( sc.match().group() );
    } catch (NumberFormatException e) {
        return Float.NaN;
    }
    

    The other solution is to prevent the exception from being thrown:

    sc.skip( number );
    String s = sc.match().group();
    if ("".equals( s )) return Float.NaN;
    return Float.parseFloat( s );
    

    Note that this question did not ask about giving an error message, but if you want to finish building a version os ScanSupport.nextFloat that works like nextName you'd probably want to include error message support and support.

  2. Background: Look at the code distributed with Lecture 10 last week. Several changes were made from the code presented previously. One change is that several error messages that had been created by concatenating numerous components have been simplified by using this.toString() in place of most of the concatenations.

    A question: Why not use this.toString to replace the concatenations in other error messages. For example, why not replace the no-such-intersection error messages in Road? (0.5 points)

    If you call this.toString from within a constructor before you have finished initializing the fields, the result can be problematic. The worst consequence is that uninitialized string fields will be null, throwing an exception when you try to concatenate them into the final string. More likely, you will get a string that does not match what you expect.

    In the case of the no-such-intersection message, the pointer to the source or destination interseciton will be null, leading to a null-pointer exception when you try to print the name of that intersection.

  3. Background: In the code distributed with Lecture 10, this code appears:
    if (sc.hasNextFloat()) {
        travelTime = sc.nextFloat();
        if (travelTime < 0.0F) {
            Errors.warn( "Negative travel time:" + this.toString() );
            travelTime = 99999.0F; // no failure needed, use bogus value
        }
    } else {
        Errors.warn( "Floating point travel time expected: Road "
            + sourceName + " " + dstName
        );
        travelTime = 99999.0F; // no failure needed, use bogus value
    }
    

    Assume you have written ScanSupport.nextFloat(sc,message) where the message parameter is the context part of the error message to output if there is no next float, and where it returns Float.NaN if there is no next float.

    A question: Rewrite the above code to use this version of ScanSupport.nextFloat. (1 point)

    travelTime = ScanSupport.nextFloat(
        sc,
        "Floating point travel time expected:"
            + sourceName + " " + dstName
    );
    if (travelTime < 0.0F) {
        Errors.warn( "Negative travel time:" + this.toString() );
        travelTime = 99999.0F; // no failure needed, use bogus value
    }