You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by gh...@apache.org on 2006/07/12 20:16:14 UTC

svn commit: r421358 - in /incubator/harmony/enhanced/classlib/trunk/modules/luni/src: main/java/java/util/Scanner.java test/java/tests/api/java/util/ScannerTest.java

Author: gharley
Date: Wed Jul 12 11:16:13 2006
New Revision: 421358

URL: http://svn.apache.org/viewvc?rev=421358&view=rev
Log:
HARMONY 838 : [luni] new methods nextFloat() and hasNextFloat() in java.util.Scanner

Modified:
    incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/util/Scanner.java
    incubator/harmony/enhanced/classlib/trunk/modules/luni/src/test/java/tests/api/java/util/ScannerTest.java

Modified: incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/util/Scanner.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/util/Scanner.java?rev=421358&r1=421357&r2=421358&view=diff
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/util/Scanner.java (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/util/Scanner.java Wed Jul 12 11:16:13 2006
@@ -83,7 +83,7 @@
 
     private Matcher matcher;
 
-    private int radix = DEFAULT_RADIX;
+    private int integerRadix = DEFAULT_RADIX;
 
     private Locale locale = Locale.getDefault();
 
@@ -104,6 +104,17 @@
     private boolean matchSuccessful = false;
     
     private DecimalFormat decimalFormat;
+    
+    private enum DataType{
+        /*
+         * Stands for Integer
+         */
+        INT,
+        /*
+         * Stands for Float
+         */
+        FLOAT;
+    }
 
     /**
      * Constructs a scanner that uses File as its input. The default charset is
@@ -480,9 +491,29 @@
         throw new NotYetImplementedException();
     }
 
-    //TODO: To implement this feature
+    /**
+     * Returns true if this scanner's next token can be translated into a valid
+     * float value. The scanner does not advance past the input.
+     * 
+     * @return true iff the next token in this scanner's input can be translated
+     *         into a valid float value
+     * @throws IllegalStateException
+     *             if the scanner has been closed
+     */
     public boolean hasNextFloat() {
-        throw new NotYetImplementedException();
+        Pattern floatPattern = getFloatPattern();
+        boolean isFloatValue = false;
+        if (hasNext(floatPattern)) {
+            String floatString = matcher.group();
+            floatString = removeLocaleInfoFromFloat(floatString);
+            try {
+                Float.parseFloat(floatString);
+                isFloatValue = true;
+            } catch (NumberFormatException e) {
+                matchSuccessful = false;
+            }
+        }
+        return isFloatValue;
     }
 
     /**
@@ -496,7 +527,7 @@
      *             if the scanner has been closed
      */
     public boolean hasNextInt() {
-        return hasNextInt(radix);
+        return hasNextInt(integerRadix);
     }
 
     /**
@@ -514,9 +545,9 @@
     public boolean hasNextInt(int radix) {
         Pattern integerPattern = getIntegerPattern(radix);
         boolean isIntValue = false;
-        String intString;
         if (hasNext(integerPattern)) {
-            intString = removeLocaleInfo(matcher.group());
+            String intString = matcher.group();
+            intString = removeLocaleInfo(intString, DataType.INT);
             try {
                 Integer.parseInt(intString, radix);
                 isIntValue = true;
@@ -729,9 +760,45 @@
         throw new NotYetImplementedException();
     }
 
-    //TODO: To implement this feature
+    /**
+     * Translates the next token in this scanner's input into a float value and
+     * returns this value. This method may be blocked when it is waiting for
+     * input to scan, even if a previous invocation of hasNextFloat() returned
+     * true. If this match succeeds, the scanner advances past the input that
+     * matched.
+     * 
+     * If the next token matches the Float regular expression successfully, the
+     * token is translated into a float value as following steps. At first all
+     * locale specific prefixes ,group separators, and locale specific suffixes
+     * are removed. Then non-ASCII digits are mapped into ASCII digits via
+     * {@link Character#digit(char, int)}}, a negative sign (-) is added if the
+     * locale specific negative prefixes and suffixes were present. At last the
+     * resulting String is passed to {@link Float#parseFloat(String)}}.If the
+     * token matches the localized NaN or infinity strings, it is also passed to
+     * {@link Float#parseFloat(String)}}.
+     * 
+     * @return the float value scanned from the input
+     * @throws IllegalStateException
+     *             if this scanner has been closed
+     * @throws NoSuchElementException
+     *             if input has been exhausted
+     * @throws InputMismatchException
+     *             if the next token can not be translated into a valid float
+     *             value
+     */
     public float nextFloat() {
-        throw new NotYetImplementedException();
+        Pattern floatPattern = getFloatPattern();
+        String floatString = next(floatPattern);
+        floatString = removeLocaleInfoFromFloat(floatString);
+        float floatValue = 0;
+        try {
+            floatValue = Float.parseFloat(floatString);
+        } catch (NumberFormatException e) {
+            matchSuccessful = false;
+            recoverPreviousStatus();
+            throw new InputMismatchException();
+        }
+        return floatValue;
     }
 
     /**
@@ -755,7 +822,7 @@
      *             value
      */
     public int nextInt() {
-        return nextInt(radix);
+        return nextInt(integerRadix);
     }
 
     /**
@@ -785,7 +852,9 @@
      *             value
      */
     public int nextInt(int radix) {
-        String intString = nextIntegerToken(radix);
+        Pattern integerPattern = getIntegerPattern(radix);
+        String intString=next(integerPattern);
+        intString = removeLocaleInfo(intString, DataType.INT);
         int intValue = 0;
         try {
             intValue = Integer.parseInt(intString, radix);
@@ -829,7 +898,7 @@
      *            the radix of this scanner
      */
     public int radix() {
-        return radix;
+        return integerRadix;
     }
 
     //TODO: To implement this feature
@@ -901,7 +970,7 @@
             throw new IllegalArgumentException(org.apache.harmony.luni.util.Msg
                     .getString("KA008", radix)); //$NON-NLS-1$
         }
-        this.radix = radix;
+        this.integerRadix = radix;
         return this;
     }
 
@@ -978,17 +1047,6 @@
     }
     
     /*
-     * Get next token if it matches integer regular expression after removing
-     * locale related information
-     */
-    private String nextIntegerToken(int radix) {
-        Pattern integerPattern = getIntegerPattern(radix);
-        String tokenString = next(integerPattern);
-        String intString = removeLocaleInfo(tokenString);
-        return intString;
-    }
-
-    /*
      * Get integer's pattern
      */
     private Pattern getIntegerPattern(int radix) {
@@ -1016,6 +1074,49 @@
         return integerPattern;
     }
 
+    /*
+     * Get pattern of float
+     */
+    private Pattern getFloatPattern() {
+        decimalFormat = (DecimalFormat) NumberFormat.getInstance(locale);
+
+        StringBuilder digit = new StringBuilder("([0-9]|(\\p{javaDigit}))"); //$NON-NLS-1$
+        StringBuilder nonZeroDigit = new StringBuilder("[\\p{javaDigit}&&[^0]]"); //$NON-NLS-1$
+        StringBuilder numeral = getNumeral(digit, nonZeroDigit);
+
+        char decimalSeparator = decimalFormat.getDecimalFormatSymbols()
+                .getDecimalSeparator();
+        StringBuilder decimalNumeral = new StringBuilder("(").append(numeral) //$NON-NLS-1$
+                .append("|").append(numeral).append("\\") //$NON-NLS-1$//$NON-NLS-2$
+                .append(decimalSeparator).append(digit).append("*+|\\").append( //$NON-NLS-1$
+                        decimalSeparator).append(digit).append("++)"); //$NON-NLS-1$
+        StringBuilder exponent = new StringBuilder("([eE][+-]?").append(digit) //$NON-NLS-1$
+                .append("+)?"); //$NON-NLS-1$
+
+        StringBuilder decimal = new StringBuilder("(([-+]?").append( //$NON-NLS-1$
+                decimalNumeral).append("(").append(exponent).append("?)") //$NON-NLS-1$ //$NON-NLS-2$
+                .append(")|(").append(addPositiveSign(decimalNumeral)).append( //$NON-NLS-1$
+                        "(").append(exponent).append("?)").append(")|(") //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+                .append(addNegativeSign(decimalNumeral)).append("(").append( //$NON-NLS-1$
+                        exponent).append("?)").append("))"); //$NON-NLS-1$ //$NON-NLS-2$
+
+        StringBuilder hexFloat = new StringBuilder("([-+]?0[xX][0-9a-fA-F]*\\") //$NON-NLS-1$
+                .append(decimalSeparator).append(
+                        "[0-9a-fA-F]+([pP][-+]?[0-9]++)?)"); //$NON-NLS-1$
+        String localNaN = decimalFormat.getDecimalFormatSymbols().getNaN();
+        String localeInfinity = decimalFormat.getDecimalFormatSymbols()
+                .getInfinity();
+        StringBuilder nonNumber = new StringBuilder("NaN|\\").append(localNaN) //$NON-NLS-1$
+                .append("|Infinity|\\").append(localeInfinity).append(""); //$NON-NLS-1$ //$NON-NLS-2$
+        StringBuilder singedNonNumber = new StringBuilder("((([-+]?(").append( //$NON-NLS-1$
+                nonNumber).append(")))|(").append(addPositiveSign(nonNumber)) //$NON-NLS-1$
+                .append(")|(").append(addNegativeSign(nonNumber)).append("))"); //$NON-NLS-1$ //$NON-NLS-2$
+
+        StringBuilder floatString = new StringBuilder().append(decimal).append(
+                "|").append(hexFloat).append("|").append(singedNonNumber); //$NON-NLS-1$ //$NON-NLS-2$
+        Pattern floatPattern = Pattern.compile(floatString.toString());
+        return floatPattern;
+    }
 
     private StringBuilder getNumeral(StringBuilder digit,
             StringBuilder nonZeroDigit) {
@@ -1067,10 +1168,36 @@
     }
 
     /*
+     * Remove locale related information from float String
+     */
+    private String removeLocaleInfoFromFloat(String floatString) {
+        // If the token is HexFloat
+        if (-1 != floatString.indexOf('x')
+                || -1 != floatString.indexOf('X')) {
+            return floatString;
+        }
+        
+        int exponentIndex;
+        String decimalNumeralString;
+        String exponentString;
+        // If the token is scientific notation
+        if (-1 != (exponentIndex = floatString.indexOf('e'))
+                || -1 != (exponentIndex = floatString.indexOf('E'))) {
+            decimalNumeralString = floatString.substring(0, exponentIndex);
+            exponentString = floatString.substring(exponentIndex + 1,
+                    floatString.length());
+            decimalNumeralString = removeLocaleInfo(decimalNumeralString,
+                    DataType.FLOAT);
+            return decimalNumeralString + "e" + exponentString; //$NON-NLS-1$ 
+        }
+        return removeLocaleInfo(floatString, DataType.FLOAT);
+    }
+    
+    /*
      * Remove the locale specific prefixes, group separators, and locale
      * specific suffixes from input string
      */
-    private String removeLocaleInfo(String token) {
+    private String removeLocaleInfo(String token, DataType type) {
         StringBuilder tokenBuilder = new StringBuilder(token);
         boolean negative = removeLocaleSign(tokenBuilder);
         // Remove group separator
@@ -1085,11 +1212,19 @@
                 .getDecimalFormatSymbols().getDecimalSeparator());
         separatorIndex = tokenBuilder.indexOf(decimalSeparator);
         StringBuilder result = new StringBuilder(""); //$NON-NLS-1$
-        
-        for (int i = 0; i < tokenBuilder.length(); i++) {
-            if (-1 != Character.digit(tokenBuilder.charAt(i),
-                    Character.MAX_RADIX)) {
-                result.append(tokenBuilder.charAt(i));
+        if (DataType.INT == type) {
+            for (int i = 0; i < tokenBuilder.length(); i++) {
+                if (-1 != Character.digit(tokenBuilder.charAt(i),
+                        Character.MAX_RADIX)) {
+                    result.append(tokenBuilder.charAt(i));
+                }
+            }
+        }
+        if (DataType.FLOAT == type) {
+            for (int i = 0; i < tokenBuilder.length(); i++) {
+                if (-1 != Character.digit(tokenBuilder.charAt(i), 10)) {
+                    result.append(Character.digit(tokenBuilder.charAt(i), 10));
+                }
             }
         }
         // Token is NaN or Infinity
@@ -1105,7 +1240,6 @@
         }
         return result.toString();
     }
-
     /*
      * remove positive and negative sign from the parameter stringBuilder, and
      * return whether the input string is negative
@@ -1285,7 +1419,8 @@
                 // nothing to do here
             }
         } catch (IOException e) {
-            readCount = (buffer.position() - oldLimit);
+            bufferLength += (buffer.position() - oldLimit);
+            readCount = -1;
             lastIOException = e;
         }
 

Modified: incubator/harmony/enhanced/classlib/trunk/modules/luni/src/test/java/tests/api/java/util/ScannerTest.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/luni/src/test/java/tests/api/java/util/ScannerTest.java?rev=421358&r1=421357&r2=421358&view=diff
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/luni/src/test/java/tests/api/java/util/ScannerTest.java (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/luni/src/test/java/tests/api/java/util/ScannerTest.java Wed Jul 12 11:16:13 2006
@@ -1307,6 +1307,101 @@
     
     /**
      * @throws IOException
+     * @tests java.util.Scanner#nextFloat()
+     */
+    public void test_nextFloat() throws IOException {
+        s = new Scanner("123 45\u0666. 123.4 .123 ");
+        s.useLocale(Locale.ENGLISH);
+        assertEquals((float)123.0, s.nextFloat());
+        assertEquals((float)456.0, s.nextFloat());
+        assertEquals((float)123.4, s.nextFloat());
+        assertEquals((float)0.123, s.nextFloat());
+        try {
+            s.nextFloat();
+            fail("Should throw NoSuchElementException");
+        } catch (NoSuchElementException e) {
+            // Expected
+        }
+
+        s = new Scanner("+123.4 -456.7 123,456.789 0.1\u06623,4");
+        s.useLocale(Locale.ENGLISH);
+        assertEquals((float)123.4, s.nextFloat());
+        assertEquals((float)-456.7, s.nextFloat());
+        assertEquals((float)123456.789, s.nextFloat());
+        try {
+            s.nextFloat();
+            fail("Should throw InputMismatchException");
+        } catch (InputMismatchException e) {
+            // Expected
+        }
+
+        // Scientific notation
+        s = new Scanner("+123.4E10 -456.7e+12 123,456.789E-10");
+        s.useLocale(Locale.ENGLISH);
+        assertEquals((float)1.234E12, s.nextFloat());
+        assertEquals((float)-4.567E14, s.nextFloat());
+        assertEquals((float)1.23456789E-5, s.nextFloat());
+
+        s = new Scanner("NaN Infinity -Infinity");
+        assertEquals(Float.NaN, s.nextFloat());
+        assertEquals(Float.POSITIVE_INFINITY, s.nextFloat());
+        assertEquals(Float.NEGATIVE_INFINITY, s.nextFloat());
+
+        String str=String.valueOf(Float.MAX_VALUE*2);
+        s=new Scanner(str);
+        assertEquals(Float.POSITIVE_INFINITY,s.nextFloat());
+        
+        /*
+         * Different locale can only recognize corresponding locale sensitive
+         * string. ',' is used in many locales as group separator.
+         */
+        s = new Scanner("23,456 23,456");
+        s.useLocale(Locale.ENGLISH);
+        assertEquals((float)23456.0, s.nextFloat());
+        s.useLocale(Locale.GERMANY);
+        assertEquals((float)23.456, s.nextFloat());
+
+        s = new Scanner("23.456 23.456");
+        s.useLocale(Locale.ENGLISH);
+        assertEquals((float)23.456, s.nextFloat());
+        s.useLocale(Locale.GERMANY);
+        assertEquals((float)23456.0, s.nextFloat());
+
+        s = new Scanner("23,456.7 23.456,7");
+        s.useLocale(Locale.ENGLISH);
+        assertEquals((float)23456.7, s.nextFloat());
+        s.useLocale(Locale.GERMANY);
+        assertEquals((float)23456.7, s.nextFloat());
+
+        s = new Scanner("-123.4 123.4- -123.4-");
+        s.useLocale(new Locale("ar", "AE"));
+        assertEquals((float)-123.4, s.nextFloat());
+        //The following test case fails on RI
+        assertEquals((float)-123.4, s.nextFloat());
+        try {
+            s.nextFloat();
+            fail("Should throw InputMismatchException");
+        } catch (InputMismatchException e) {
+            // Expected
+        }
+
+        s = new Scanner("(123) 123- -123");
+        s.useLocale(new Locale("mk", "MK"));
+        assertEquals((float)-123.0, s.nextFloat());
+        try {
+            s.nextFloat();
+            fail("Should throw InputMismatchException");
+        } catch (InputMismatchException e) {
+            // Expected
+        }
+        // Skip the un-recognizable token 123-.
+        assertEquals("123-", s.next());
+        assertEquals((float)-123.0, s.nextFloat());
+
+    }
+    
+    /**
+     * @throws IOException
      * @tests java.util.Scanner#hasNext()
      */
     public void test_hasNext() throws IOException {
@@ -1923,7 +2018,129 @@
         assertTrue(s.hasNextInt());
         assertEquals(-123, s.nextInt());
     }
+    
+    /**
+     * @throws IOException
+     * @tests java.util.Scanner#hasNextFloat()
+     */
+    public void test_hasNextFloat() throws IOException {
+        s = new Scanner("123 45\u0666. 123.4 .123 ");
+        s.useLocale(Locale.ENGLISH);
+        assertTrue(s.hasNextFloat());
+        assertEquals((float)123.0, s.nextFloat());
+        assertTrue(s.hasNextFloat());
+        assertEquals((float)456.0, s.nextFloat());
+        assertTrue(s.hasNextFloat());
+        assertEquals((float)123.4, s.nextFloat());
+        assertTrue(s.hasNextFloat());
+        assertEquals((float)0.123, s.nextFloat());
+        assertFalse(s.hasNextFloat());
+        try {
+            s.nextFloat();
+            fail("Should throw NoSuchElementException");
+        } catch (NoSuchElementException e) {
+            // Expected
+        }
+
+        s = new Scanner("+123.4 -456.7 123,456.789 0.1\u06623,4");
+        s.useLocale(Locale.ENGLISH);
+        assertTrue(s.hasNextFloat());
+        assertEquals((float)123.4, s.nextFloat());
+        assertTrue(s.hasNextFloat());
+        assertEquals((float)-456.7, s.nextFloat());
+        assertTrue(s.hasNextFloat());
+        assertEquals((float)123456.789, s.nextFloat());
+        assertFalse(s.hasNextFloat());
+        try {
+            s.nextFloat();
+            fail("Should throw InputMismatchException");
+        } catch (InputMismatchException e) {
+            // Expected
+        }
+
+        // Scientific notation
+        s = new Scanner("+123.4E10 -456.7e+12 123,456.789E-10");
+        s.useLocale(Locale.ENGLISH);
+        assertTrue(s.hasNextFloat());
+        assertEquals((float)1.234E12, s.nextFloat());
+        assertTrue(s.hasNextFloat());
+        assertEquals((float)-4.567E14, s.nextFloat());
+        assertTrue(s.hasNextFloat());
+        assertEquals((float)1.23456789E-5, s.nextFloat());
+
+        s = new Scanner("NaN Infinity -Infinity");
+        assertTrue(s.hasNextFloat());
+        assertEquals(Float.NaN, s.nextFloat());
+        assertTrue(s.hasNextFloat());
+        assertEquals(Float.POSITIVE_INFINITY, s.nextFloat());
+        assertTrue(s.hasNextFloat());
+        assertEquals(Float.NEGATIVE_INFINITY, s.nextFloat());
+
+        String str=String.valueOf(Float.MAX_VALUE*2);
+        s=new Scanner(str);
+        assertTrue(s.hasNextFloat());
+        assertEquals(Float.POSITIVE_INFINITY,s.nextFloat());
+        
+        /*
+         * Different locale can only recognize corresponding locale sensitive
+         * string. ',' is used in many locales as group separator.
+         */
+        s = new Scanner("23,456 23,456");
+        s.useLocale(Locale.ENGLISH);
+        assertTrue(s.hasNextFloat());
+        assertEquals((float)23456.0, s.nextFloat());
+        s.useLocale(Locale.GERMANY);
+        assertTrue(s.hasNextFloat());
+        assertEquals((float)23.456, s.nextFloat());
+
+        s = new Scanner("23.456 23.456");
+        s.useLocale(Locale.ENGLISH);
+        assertTrue(s.hasNextFloat());
+        assertEquals((float)23.456, s.nextFloat());
+        s.useLocale(Locale.GERMANY);
+        assertTrue(s.hasNextFloat());
+        assertEquals((float)23456.0, s.nextFloat());
+
+        s = new Scanner("23,456.7 23.456,7");
+        s.useLocale(Locale.ENGLISH);
+        assertTrue(s.hasNextFloat());
+        assertEquals((float)23456.7, s.nextFloat());
+        s.useLocale(Locale.GERMANY);
+        assertTrue(s.hasNextFloat());
+        assertEquals((float)23456.7, s.nextFloat());
 
+        s = new Scanner("-123.4 123.4- -123.4-");
+        s.useLocale(new Locale("ar", "AE"));
+        assertTrue(s.hasNextFloat());
+        assertEquals((float)-123.4, s.nextFloat());
+        //The following test case fails on RI
+        assertTrue(s.hasNextFloat());
+        assertEquals((float)-123.4, s.nextFloat());
+        try {
+            s.nextFloat();
+            fail("Should throw InputMismatchException");
+        } catch (InputMismatchException e) {
+            // Expected
+        }
+
+        s = new Scanner("(123) 123- -123");
+        s.useLocale(new Locale("mk", "MK"));
+        assertTrue(s.hasNextFloat());
+        assertEquals((float)-123.0, s.nextFloat());
+        assertFalse(s.hasNextFloat());
+        try {
+            s.nextFloat();
+            fail("Should throw InputMismatchException");
+        } catch (InputMismatchException e) {
+            // Expected
+        }
+        // Skip the un-recognizable token 123-.
+        assertEquals("123-", s.next());
+        assertTrue(s.hasNextFloat());
+        assertEquals((float)-123.0, s.nextFloat());
+
+    }
+    
     private static class MockStringReader extends StringReader {
 
         public MockStringReader(String param) {