< prev index next >

src/java.base/share/classes/java/util/Scanner.java

Print this page
rev 52910 : 8236201: Better Scanner conversions
Reviewed-by: ahgross, rhalade, rriggs, skoivu, smarks, andrew
   1 /*
   2  * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any


 411         Pattern bp = boolPattern;
 412         if (bp == null)
 413             boolPattern = bp = Pattern.compile(BOOLEAN_PATTERN,
 414                                           Pattern.CASE_INSENSITIVE);
 415         return bp;
 416     }
 417 
 418     /**
 419      * Fields and methods to match bytes, shorts, ints, and longs
 420      */
 421     private Pattern integerPattern;
 422     private String digits = "0123456789abcdefghijklmnopqrstuvwxyz";
 423     private String non0Digit = "[\\p{javaDigit}&&[^0]]";
 424     private int SIMPLE_GROUP_INDEX = 5;
 425     private String buildIntegerPatternString() {
 426         String radixDigits = digits.substring(0, radix);
 427         // \\p{javaDigit} is not guaranteed to be appropriate
 428         // here but what can we do? The final authority will be
 429         // whatever parse method is invoked, so ultimately the
 430         // Scanner will do the right thing
 431         String digit = "((?i)["+radixDigits+"]|\\p{javaDigit})";
 432         String groupedNumeral = "("+non0Digit+digit+"?"+digit+"?("+
 433                                 groupSeparator+digit+digit+digit+")+)";
 434         // digit++ is the possessive form which is necessary for reducing
 435         // backtracking that would otherwise cause unacceptable performance
 436         String numeral = "(("+ digit+"++)|"+groupedNumeral+")";
 437         String javaStyleInteger = "([-+]?(" + numeral + "))";
 438         String negativeInteger = negativePrefix + numeral + negativeSuffix;
 439         String positiveInteger = positivePrefix + numeral + positiveSuffix;
 440         return "("+ javaStyleInteger + ")|(" +
 441             positiveInteger + ")|(" +
 442             negativeInteger + ")";
 443     }
 444     private Pattern integerPattern() {
 445         if (integerPattern == null) {
 446             integerPattern = patternCache.forName(buildIntegerPatternString());
 447         }
 448         return integerPattern;
 449     }
 450 
 451     /**


 461         Pattern sp = separatorPattern;
 462         if (sp == null)
 463             separatorPattern = sp = Pattern.compile(LINE_SEPARATOR_PATTERN);
 464         return sp;
 465     }
 466 
 467     private static Pattern linePattern() {
 468         Pattern lp = linePattern;
 469         if (lp == null)
 470             linePattern = lp = Pattern.compile(LINE_PATTERN);
 471         return lp;
 472     }
 473 
 474     /**
 475      * Fields and methods to match floats and doubles
 476      */
 477     private Pattern floatPattern;
 478     private Pattern decimalPattern;
 479     private void buildFloatAndDecimalPattern() {
 480         // \\p{javaDigit} may not be perfect, see above
 481         String digit = "([0-9]|(\\p{javaDigit}))";
 482         String exponent = "([eE][+-]?"+digit+"+)?";
 483         String groupedNumeral = "("+non0Digit+digit+"?"+digit+"?("+
 484                                 groupSeparator+digit+digit+digit+")+)";
 485         // Once again digit++ is used for performance, as above
 486         String numeral = "(("+digit+"++)|"+groupedNumeral+")";
 487         String decimalNumeral = "("+numeral+"|"+numeral +
 488             decimalSeparator + digit + "*+|"+ decimalSeparator +
 489             digit + "++)";
 490         String nonNumber = "(NaN|"+nanString+"|Infinity|"+
 491                                infinityString+")";
 492         String positiveFloat = "(" + positivePrefix + decimalNumeral +
 493                             positiveSuffix + exponent + ")";
 494         String negativeFloat = "(" + negativePrefix + decimalNumeral +
 495                             negativeSuffix + exponent + ")";
 496         String decimal = "(([-+]?" + decimalNumeral + exponent + ")|"+
 497             positiveFloat + "|" + negativeFloat + ")";
 498         String hexFloat =
 499             "[-+]?0[xX][0-9a-fA-F]*\\.[0-9a-fA-F]+([pP][-+]?[0-9]+)?";
 500         String positiveNonNumber = "(" + positivePrefix + nonNumber +
 501                             positiveSuffix + ")";


1272         if (nf instanceof DecimalFormat) {
1273              df = (DecimalFormat) nf;
1274         } else {
1275 
1276             // In case where NumberFormat.getNumberInstance() returns
1277             // other instance (non DecimalFormat) based on the provider
1278             // used and java.text.spi.NumberFormatProvider implementations,
1279             // DecimalFormat constructor is used to obtain the instance
1280             LocaleProviderAdapter adapter = LocaleProviderAdapter
1281                     .getAdapter(NumberFormatProvider.class, locale);
1282             if (!(adapter instanceof ResourceBundleBasedAdapter)) {
1283                 adapter = LocaleProviderAdapter.getResourceBundleBased();
1284             }
1285             String[] all = adapter.getLocaleResources(locale)
1286                     .getNumberPatterns();
1287             df = new DecimalFormat(all[0], dfs);
1288         }
1289 
1290         // These must be literalized to avoid collision with regex
1291         // metacharacters such as dot or parenthesis
1292         groupSeparator =   "\\" + dfs.getGroupingSeparator();
1293         decimalSeparator = "\\" + dfs.getDecimalSeparator();
1294 
1295         // Quoting the nonzero length locale-specific things
1296         // to avoid potential conflict with metacharacters
1297         nanString = "\\Q" + dfs.getNaN() + "\\E";
1298         infinityString = "\\Q" + dfs.getInfinity() + "\\E";
1299         positivePrefix = df.getPositivePrefix();
1300         if (!positivePrefix.isEmpty())
1301             positivePrefix = "\\Q" + positivePrefix + "\\E";
1302         negativePrefix = df.getNegativePrefix();
1303         if (!negativePrefix.isEmpty())
1304             negativePrefix = "\\Q" + negativePrefix + "\\E";
1305         positiveSuffix = df.getPositiveSuffix();
1306         if (!positiveSuffix.isEmpty())
1307             positiveSuffix = "\\Q" + positiveSuffix + "\\E";
1308         negativeSuffix = df.getNegativeSuffix();
1309         if (!negativeSuffix.isEmpty())
1310             negativeSuffix = "\\Q" + negativeSuffix + "\\E";
1311 
1312         // Force rebuilding and recompilation of locale dependent
1313         // primitive patterns
1314         integerPattern = null;
1315         floatPattern = null;
1316 
1317         return this;
1318     }
1319 
1320     /**
1321      * Returns this scanner's default radix.
1322      *
1323      * <p>A scanner's radix affects elements of its default
1324      * number matching regular expressions; see
1325      * <a href= "#localized-numbers">localized numbers</a> above.
1326      *
1327      * @return the default radix of this scanner
1328      */
1329     public int radix() {
1330         return this.defaultRadix;


   1 /*
   2  * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any


 411         Pattern bp = boolPattern;
 412         if (bp == null)
 413             boolPattern = bp = Pattern.compile(BOOLEAN_PATTERN,
 414                                           Pattern.CASE_INSENSITIVE);
 415         return bp;
 416     }
 417 
 418     /**
 419      * Fields and methods to match bytes, shorts, ints, and longs
 420      */
 421     private Pattern integerPattern;
 422     private String digits = "0123456789abcdefghijklmnopqrstuvwxyz";
 423     private String non0Digit = "[\\p{javaDigit}&&[^0]]";
 424     private int SIMPLE_GROUP_INDEX = 5;
 425     private String buildIntegerPatternString() {
 426         String radixDigits = digits.substring(0, radix);
 427         // \\p{javaDigit} is not guaranteed to be appropriate
 428         // here but what can we do? The final authority will be
 429         // whatever parse method is invoked, so ultimately the
 430         // Scanner will do the right thing
 431         String digit = "((?i)["+radixDigits+"\\p{javaDigit}])";
 432         String groupedNumeral = "("+non0Digit+digit+"?"+digit+"?("+
 433                                 groupSeparator+digit+digit+digit+")+)";
 434         // digit++ is the possessive form which is necessary for reducing
 435         // backtracking that would otherwise cause unacceptable performance
 436         String numeral = "(("+ digit+"++)|"+groupedNumeral+")";
 437         String javaStyleInteger = "([-+]?(" + numeral + "))";
 438         String negativeInteger = negativePrefix + numeral + negativeSuffix;
 439         String positiveInteger = positivePrefix + numeral + positiveSuffix;
 440         return "("+ javaStyleInteger + ")|(" +
 441             positiveInteger + ")|(" +
 442             negativeInteger + ")";
 443     }
 444     private Pattern integerPattern() {
 445         if (integerPattern == null) {
 446             integerPattern = patternCache.forName(buildIntegerPatternString());
 447         }
 448         return integerPattern;
 449     }
 450 
 451     /**


 461         Pattern sp = separatorPattern;
 462         if (sp == null)
 463             separatorPattern = sp = Pattern.compile(LINE_SEPARATOR_PATTERN);
 464         return sp;
 465     }
 466 
 467     private static Pattern linePattern() {
 468         Pattern lp = linePattern;
 469         if (lp == null)
 470             linePattern = lp = Pattern.compile(LINE_PATTERN);
 471         return lp;
 472     }
 473 
 474     /**
 475      * Fields and methods to match floats and doubles
 476      */
 477     private Pattern floatPattern;
 478     private Pattern decimalPattern;
 479     private void buildFloatAndDecimalPattern() {
 480         // \\p{javaDigit} may not be perfect, see above
 481         String digit = "(([0-9\\p{javaDigit}]))";
 482         String exponent = "([eE][+-]?"+digit+"+)?";
 483         String groupedNumeral = "("+non0Digit+digit+"?"+digit+"?("+
 484                                 groupSeparator+digit+digit+digit+")+)";
 485         // Once again digit++ is used for performance, as above
 486         String numeral = "(("+digit+"++)|"+groupedNumeral+")";
 487         String decimalNumeral = "("+numeral+"|"+numeral +
 488             decimalSeparator + digit + "*+|"+ decimalSeparator +
 489             digit + "++)";
 490         String nonNumber = "(NaN|"+nanString+"|Infinity|"+
 491                                infinityString+")";
 492         String positiveFloat = "(" + positivePrefix + decimalNumeral +
 493                             positiveSuffix + exponent + ")";
 494         String negativeFloat = "(" + negativePrefix + decimalNumeral +
 495                             negativeSuffix + exponent + ")";
 496         String decimal = "(([-+]?" + decimalNumeral + exponent + ")|"+
 497             positiveFloat + "|" + negativeFloat + ")";
 498         String hexFloat =
 499             "[-+]?0[xX][0-9a-fA-F]*\\.[0-9a-fA-F]+([pP][-+]?[0-9]+)?";
 500         String positiveNonNumber = "(" + positivePrefix + nonNumber +
 501                             positiveSuffix + ")";


1272         if (nf instanceof DecimalFormat) {
1273              df = (DecimalFormat) nf;
1274         } else {
1275 
1276             // In case where NumberFormat.getNumberInstance() returns
1277             // other instance (non DecimalFormat) based on the provider
1278             // used and java.text.spi.NumberFormatProvider implementations,
1279             // DecimalFormat constructor is used to obtain the instance
1280             LocaleProviderAdapter adapter = LocaleProviderAdapter
1281                     .getAdapter(NumberFormatProvider.class, locale);
1282             if (!(adapter instanceof ResourceBundleBasedAdapter)) {
1283                 adapter = LocaleProviderAdapter.getResourceBundleBased();
1284             }
1285             String[] all = adapter.getLocaleResources(locale)
1286                     .getNumberPatterns();
1287             df = new DecimalFormat(all[0], dfs);
1288         }
1289 
1290         // These must be literalized to avoid collision with regex
1291         // metacharacters such as dot or parenthesis
1292         groupSeparator =   "\\x{" + Integer.toHexString(dfs.getGroupingSeparator()) + "}";
1293         decimalSeparator = "\\x{" + Integer.toHexString(dfs.getDecimalSeparator()) + "}";
1294 
1295         // Quoting the nonzero length locale-specific things
1296         // to avoid potential conflict with metacharacters
1297         nanString = Pattern.quote(dfs.getNaN());
1298         infinityString = Pattern.quote(dfs.getInfinity());
1299         positivePrefix = df.getPositivePrefix();
1300         if (!positivePrefix.isEmpty())
1301             positivePrefix = Pattern.quote(positivePrefix);
1302         negativePrefix = df.getNegativePrefix();
1303         if (!negativePrefix.isEmpty())
1304             negativePrefix = Pattern.quote(negativePrefix);
1305         positiveSuffix = df.getPositiveSuffix();
1306         if (!positiveSuffix.isEmpty())
1307             positiveSuffix = Pattern.quote(positiveSuffix);
1308         negativeSuffix = df.getNegativeSuffix();
1309         if (!negativeSuffix.isEmpty())
1310             negativeSuffix = Pattern.quote(negativeSuffix);
1311 
1312         // Force rebuilding and recompilation of locale dependent
1313         // primitive patterns
1314         integerPattern = null;
1315         floatPattern = null;
1316 
1317         return this;
1318     }
1319 
1320     /**
1321      * Returns this scanner's default radix.
1322      *
1323      * <p>A scanner's radix affects elements of its default
1324      * number matching regular expressions; see
1325      * <a href= "#localized-numbers">localized numbers</a> above.
1326      *
1327      * @return the default radix of this scanner
1328      */
1329     public int radix() {
1330         return this.defaultRadix;


< prev index next >