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) {