< prev index next >

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

Print this page
rev 12670 : 8072722: add stream support to Scanner
Reviewed-by: psandoz, chegar
   1 /*
   2  * Copyright (c) 2003, 2013, 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
  23  * questions.
  24  */
  25 
  26 package java.util;
  27 
  28 import java.nio.file.Path;
  29 import java.nio.file.Files;
  30 import java.util.regex.*;
  31 import java.io.*;
  32 import java.math.*;
  33 import java.nio.*;
  34 import java.nio.channels.*;
  35 import java.nio.charset.*;


  36 import java.text.*;
  37 import java.util.Locale;



  38 
  39 import sun.misc.LRUCache;
  40 
  41 /**
  42  * A simple text scanner which can parse primitive types and strings using
  43  * regular expressions.
  44  *
  45  * <p>A {@code Scanner} breaks its input into tokens using a
  46  * delimiter pattern, which by default matches whitespace. The resulting
  47  * tokens may then be converted into values of different types using the
  48  * various {@code next} methods.
  49  *
  50  * <p>For example, this code allows a user to read a number from
  51  * {@code System.in}:
  52  * <blockquote><pre>{@code
  53  *     Scanner sc = new Scanner(System.in);
  54  *     int i = sc.nextInt();
  55  * }</pre></blockquote>
  56  *
  57  * <p>As another example, this code allows {@code long} types to be


  79  * <blockquote><pre>{@code
  80  *     1
  81  *     2
  82  *     red
  83  *     blue
  84  * }</pre></blockquote>
  85  *
  86  * <p>The same output can be generated with this code, which uses a regular
  87  * expression to parse all four tokens at once:
  88  * <blockquote><pre>{@code
  89  *     String input = "1 fish 2 fish red fish blue fish";
  90  *     Scanner s = new Scanner(input);
  91  *     s.findInLine("(\\d+) fish (\\d+) fish (\\w+) fish (\\w+)");
  92  *     MatchResult result = s.match();
  93  *     for (int i=1; i<=result.groupCount(); i++)
  94  *         System.out.println(result.group(i));
  95  *     s.close();
  96  * }</pre></blockquote>
  97  *
  98  * <p>The <a name="default-delimiter">default whitespace delimiter</a> used
  99  * by a scanner is as recognized by {@link java.lang.Character}.{@link
 100  * java.lang.Character#isWhitespace(char) isWhitespace}. The {@link #reset}
 101  * method will reset the value of the scanner's delimiter to the default
 102  * whitespace delimiter regardless of whether it was previously changed.
 103  *
 104  * <p>A scanning operation may block waiting for input.
 105  *
 106  * <p>The {@link #next} and {@link #hasNext} methods and their
 107  * primitive-type companion methods (such as {@link #nextInt} and
 108  * {@link #hasNextInt}) first skip any input that matches the delimiter
 109  * pattern, and then attempt to return the next token. Both {@code hasNext}
 110  * and {@code next} methods may block waiting for further input.  Whether a
 111  * {@code hasNext} method blocks has no connection to whether or not its
 112  * associated {@code next} method will block.
 113  *
 114  * <p> The {@link #findInLine}, {@link #findWithinHorizon}, and {@link #skip}



 115  * methods operate independently of the delimiter pattern. These methods will
 116  * attempt to match the specified pattern with no regard to delimiters in the
 117  * input and thus can be used in special circumstances where delimiters are
 118  * not relevant. These methods may block waiting for more input.
 119  *
 120  * <p>When a scanner throws an {@link InputMismatchException}, the scanner
 121  * will not pass the token that caused the exception, so that it may be
 122  * retrieved or skipped via some other method.
 123  *
 124  * <p>Depending upon the type of delimiting pattern, empty tokens may be
 125  * returned. For example, the pattern {@code "\\s+"} will return no empty
 126  * tokens since it matches multiple instances of the delimiter. The delimiting
 127  * pattern {@code "\\s"} could return empty tokens since it only passes one
 128  * space at a time.
 129  *
 130  * <p> A scanner can read text from any object which implements the {@link
 131  * java.lang.Readable} interface.  If an invocation of the underlying
 132  * readable's {@link java.lang.Readable#read} method throws an {@link
 133  * java.io.IOException} then the scanner assumes that the end of the input
 134  * has been reached.  The most recent {@code IOException} thrown by the
 135  * underlying readable can be retrieved via the {@link #ioException} method.
 136  *
 137  * <p>When a {@code Scanner} is closed, it will close its input source
 138  * if the source implements the {@link java.io.Closeable} interface.
 139  *
 140  * <p>A {@code Scanner} is not safe for multithreaded use without
 141  * external synchronization.
 142  *
 143  * <p>Unless otherwise mentioned, passing a {@code null} parameter into
 144  * any method of a {@code Scanner} will cause a
 145  * {@code NullPointerException} to be thrown.
 146  *
 147  * <p>A scanner will default to interpreting numbers as decimal unless a
 148  * different radix has been set by using the {@link #useRadix} method. The
 149  * {@link #reset} method will reset the value of the scanner's radix to
 150  * {@code 10} regardless of whether it was previously changed.
 151  *
 152  * <h3> <a name="localized-numbers">Localized numbers</a> </h3>
 153  *
 154  * <p> An instance of this class is capable of scanning numbers in the standard
 155  * formats as well as in the formats of the scanner's locale. A scanner's
 156  * <a name="initial-locale">initial locale </a>is the value returned by the {@link
 157  * java.util.Locale#getDefault(Locale.Category)
 158  * Locale.getDefault(Locale.Category.FORMAT)} method; it may be changed via the {@link
 159  * #useLocale} method. The {@link #reset} method will reset the value of the
 160  * scanner's locale to the initial locale regardless of whether it was
 161  * previously changed.
 162  *
 163  * <p>The localized formats are defined in terms of the following parameters,
 164  * which for a particular locale are taken from that locale's {@link
 165  * java.text.DecimalFormat DecimalFormat} object, {@code df}, and its and
 166  * {@link java.text.DecimalFormatSymbols DecimalFormatSymbols} object,
 167  * {@code dfs}.
 168  *
 169  * <blockquote><dl>
 170  *     <dt><i>LocalGroupSeparator&nbsp;&nbsp;</i>
 171  *         <dd>The character used to separate thousands groups,
 172  *         <i>i.e.,</i>&nbsp;{@code dfs.}{@link
 173  *         java.text.DecimalFormatSymbols#getGroupingSeparator
 174  *         getGroupingSeparator()}
 175  *     <dt><i>LocalDecimalSeparator&nbsp;&nbsp;</i>
 176  *         <dd>The character used for the decimal point,
 177  *     <i>i.e.,</i>&nbsp;{@code dfs.}{@link
 178  *     java.text.DecimalFormatSymbols#getDecimalSeparator
 179  *     getDecimalSeparator()}


 357     // The default radix for this scanner
 358     private int defaultRadix = 10;
 359 
 360     // The locale used by this scanner
 361     private Locale locale = null;
 362 
 363     // A cache of the last few recently used Patterns
 364     private LRUCache<String,Pattern> patternCache =
 365     new LRUCache<String,Pattern>(7) {
 366         protected Pattern create(String s) {
 367             return Pattern.compile(s);
 368         }
 369         protected boolean hasName(Pattern p, String s) {
 370             return p.pattern().equals(s);
 371         }
 372     };
 373 
 374     // A holder of the last IOException encountered
 375     private IOException lastException;
 376 





 377     // A pattern for java whitespace
 378     private static Pattern WHITESPACE_PATTERN = Pattern.compile(
 379                                                 "\\p{javaWhitespace}+");
 380 
 381     // A pattern for any token
 382     private static Pattern FIND_ANY_PATTERN = Pattern.compile("(?s).*");
 383 
 384     // A pattern for non-ASCII digits
 385     private static Pattern NON_ASCII_DIGIT = Pattern.compile(
 386         "[\\p{javaDigit}&&[^0-9]]");
 387 
 388     // Fields and methods to support scanning primitive types
 389 
 390     /**
 391      * Locale dependent values used to scan numbers
 392      */
 393     private String groupSeparator = "\\,";
 394     private String decimalSeparator = "\\.";
 395     private String nanString = "NaN";
 396     private String infinityString = "Infinity";


 978             }
 979             // Last token; Match the pattern here or throw
 980             matcher.usePattern(pattern);
 981             matcher.region(position, buf.limit());
 982             if (matcher.matches()) {
 983                 String s = matcher.group();
 984                 position = matcher.end();
 985                 return s;
 986             }
 987             // Last piece does not match
 988             return null;
 989         }
 990 
 991         // There is a partial token in the buffer; must read more
 992         // to complete it
 993         needInput = true;
 994         return null;
 995     }
 996 
 997     // Finds the specified pattern in the buffer up to horizon.
 998     // Returns a match for the specified input pattern.
 999     private String findPatternInBuffer(Pattern pattern, int horizon) {

1000         matchValid = false;
1001         matcher.usePattern(pattern);
1002         int bufferLimit = buf.limit();
1003         int horizonLimit = -1;
1004         int searchLimit = bufferLimit;
1005         if (horizon > 0) {
1006             horizonLimit = position + horizon;
1007             if (horizonLimit < bufferLimit)
1008                 searchLimit = horizonLimit;
1009         }
1010         matcher.region(position, searchLimit);
1011         if (matcher.find()) {
1012             if (matcher.hitEnd() && (!sourceClosed)) {
1013                 // The match may be longer if didn't hit horizon or real end
1014                 if (searchLimit != horizonLimit) {
1015                      // Hit an artificial end; try to extend the match
1016                     needInput = true;
1017                     return null;
1018                 }
1019                 // The match could go away depending on what is next
1020                 if ((searchLimit == horizonLimit) && matcher.requireEnd()) {
1021                     // Rare case: we hit the end of input and it happens
1022                     // that it is at the horizon and the end of input is
1023                     // required for the match.
1024                     needInput = true;
1025                     return null;
1026                 }
1027             }
1028             // Did not hit end, or hit real end, or hit horizon
1029             position = matcher.end();
1030             return matcher.group();
1031         }
1032 
1033         if (sourceClosed)
1034             return null;
1035 
1036         // If there is no specified horizon, or if we have not searched
1037         // to the specified horizon yet, get more input
1038         if ((horizon == 0) || (searchLimit != horizonLimit))
1039             needInput = true;
1040         return null;
1041     }
1042 
1043     // Returns a match for the specified input pattern anchored at
1044     // the current position
1045     private String matchPatternInBuffer(Pattern pattern) {

1046         matchValid = false;
1047         matcher.usePattern(pattern);
1048         matcher.region(position, buf.limit());
1049         if (matcher.lookingAt()) {
1050             if (matcher.hitEnd() && (!sourceClosed)) {
1051                 // Get more input and try again
1052                 needInput = true;
1053                 return null;
1054             }
1055             position = matcher.end();
1056             return matcher.group();
1057         }
1058 
1059         if (sourceClosed)
1060             return null;
1061 
1062         // Read more to find pattern
1063         needInput = true;
1064         return null;
1065     }
1066 
1067     // Throws if the scanner is closed
1068     private void ensureOpen() {
1069         if (closed)
1070             throw new IllegalStateException("Scanner closed");
1071     }
1072 
1073     // Public methods
1074 
1075     /**
1076      * Closes this scanner.
1077      *
1078      * <p> If this scanner has not yet been closed then if its underlying
1079      * {@linkplain java.lang.Readable readable} also implements the {@link
1080      * java.io.Closeable} interface then the readable's {@code close} method
1081      * will be invoked.  If this scanner is already closed then invoking this
1082      * method will have no effect.
1083      *
1084      * <p>Attempting to perform search operations after a scanner has


1111         return lastException;
1112     }
1113 
1114     /**
1115      * Returns the {@code Pattern} this {@code Scanner} is currently
1116      * using to match delimiters.
1117      *
1118      * @return this scanner's delimiting pattern.
1119      */
1120     public Pattern delimiter() {
1121         return delimPattern;
1122     }
1123 
1124     /**
1125      * Sets this scanner's delimiting pattern to the specified pattern.
1126      *
1127      * @param pattern A delimiting pattern
1128      * @return this scanner
1129      */
1130     public Scanner useDelimiter(Pattern pattern) {

1131         delimPattern = pattern;
1132         return this;
1133     }
1134 
1135     /**
1136      * Sets this scanner's delimiting pattern to a pattern constructed from
1137      * the specified {@code String}.
1138      *
1139      * <p> An invocation of this method of the form
1140      * {@code useDelimiter(pattern)} behaves in exactly the same way as the
1141      * invocation {@code useDelimiter(Pattern.compile(pattern))}.
1142      *
1143      * <p> Invoking the {@link #reset} method will set the scanner's delimiter
1144      * to the <a href= "#default-delimiter">default</a>.
1145      *
1146      * @param pattern A string specifying a delimiting pattern
1147      * @return this scanner
1148      */
1149     public Scanner useDelimiter(String pattern) {

1150         delimPattern = patternCache.forName(pattern);
1151         return this;
1152     }
1153 
1154     /**
1155      * Returns this scanner's locale.
1156      *
1157      * <p>A scanner's locale affects many elements of its default
1158      * primitive matching regular expressions; see
1159      * <a href= "#localized-numbers">localized numbers</a> above.
1160      *
1161      * @return this scanner's locale
1162      */
1163     public Locale locale() {
1164         return this.locale;
1165     }
1166 
1167     /**
1168      * Sets this scanner's locale to the specified locale.
1169      *
1170      * <p>A scanner's locale affects many elements of its default
1171      * primitive matching regular expressions; see
1172      * <a href= "#localized-numbers">localized numbers</a> above.
1173      *
1174      * <p>Invoking the {@link #reset} method will set the scanner's locale to
1175      * the <a href= "#initial-locale">initial locale</a>.
1176      *
1177      * @param locale A string specifying the locale to use
1178      * @return this scanner
1179      */
1180     public Scanner useLocale(Locale locale) {
1181         if (locale.equals(this.locale))
1182             return this;
1183 

1184         this.locale = locale;
1185         DecimalFormat df =
1186             (DecimalFormat)NumberFormat.getNumberInstance(locale);
1187         DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(locale);
1188 
1189         // These must be literalized to avoid collision with regex
1190         // metacharacters such as dot or parenthesis
1191         groupSeparator =   "\\" + dfs.getGroupingSeparator();
1192         decimalSeparator = "\\" + dfs.getDecimalSeparator();
1193 
1194         // Quoting the nonzero length locale-specific things
1195         // to avoid potential conflict with metacharacters
1196         nanString = "\\Q" + dfs.getNaN() + "\\E";
1197         infinityString = "\\Q" + dfs.getInfinity() + "\\E";
1198         positivePrefix = df.getPositivePrefix();
1199         if (positivePrefix.length() > 0)
1200             positivePrefix = "\\Q" + positivePrefix + "\\E";
1201         negativePrefix = df.getNegativePrefix();
1202         if (negativePrefix.length() > 0)
1203             negativePrefix = "\\Q" + negativePrefix + "\\E";


1219     /**
1220      * Returns this scanner's default radix.
1221      *
1222      * <p>A scanner's radix affects elements of its default
1223      * number matching regular expressions; see
1224      * <a href= "#localized-numbers">localized numbers</a> above.
1225      *
1226      * @return the default radix of this scanner
1227      */
1228     public int radix() {
1229         return this.defaultRadix;
1230     }
1231 
1232     /**
1233      * Sets this scanner's default radix to the specified radix.
1234      *
1235      * <p>A scanner's radix affects elements of its default
1236      * number matching regular expressions; see
1237      * <a href= "#localized-numbers">localized numbers</a> above.
1238      *
1239      * <p>If the radix is less than {@code Character.MIN_RADIX}
1240      * or greater than {@code Character.MAX_RADIX}, then an
1241      * {@code IllegalArgumentException} is thrown.
1242      *
1243      * <p>Invoking the {@link #reset} method will set the scanner's radix to
1244      * {@code 10}.
1245      *
1246      * @param radix The radix to use when scanning numbers
1247      * @return this scanner
1248      * @throws IllegalArgumentException if radix is out of range
1249      */
1250     public Scanner useRadix(int radix) {
1251         if ((radix < Character.MIN_RADIX) || (radix > Character.MAX_RADIX))
1252             throw new IllegalArgumentException("radix:"+radix);
1253 
1254         if (this.defaultRadix == radix)
1255             return this;

1256         this.defaultRadix = radix;
1257         // Force rebuilding and recompilation of radix dependent patterns
1258         integerPattern = null;
1259         return this;
1260     }
1261 
1262     // The next operation should occur in the specified radix but
1263     // the default is left untouched.
1264     private void setRadix(int radix) {
1265         if (this.radix != radix) {
1266             // Force rebuilding and recompilation of radix dependent patterns
1267             integerPattern = null;
1268             this.radix = radix;
1269         }
1270     }
1271 
1272     /**
1273      * Returns the match result of the last scanning operation performed
1274      * by this scanner. This method throws {@code IllegalStateException}
1275      * if no match has been performed, or if the last match was
1276      * not successful.
1277      *
1278      * <p>The various {@code next}methods of {@code Scanner}
1279      * make a match result available if they complete without throwing an
1280      * exception. For instance, after an invocation of the {@link #nextInt}
1281      * method that returned an int, this method returns a
1282      * {@code MatchResult} for the search of the
1283      * <a href="#Integer-regex"><i>Integer</i></a> regular expression
1284      * defined above. Similarly the {@link #findInLine},
1285      * {@link #findWithinHorizon}, and {@link #skip} methods will make a
1286      * match available if they succeed.
1287      *
1288      * @return a match result for the last match operation
1289      * @throws IllegalStateException  If no match result is available
1290      */
1291     public MatchResult match() {
1292         if (!matchValid)
1293             throw new IllegalStateException("No match result available");
1294         return matcher.toMatchResult();
1295     }
1296 
1297     /**
1298      * <p>Returns the string representation of this {@code Scanner}. The
1299      * string representation of a {@code Scanner} contains information
1300      * that may be useful for debugging. The exact format is unspecified.
1301      *
1302      * @return  The string representation of this scanner
1303      */
1304     public String toString() {
1305         StringBuilder sb = new StringBuilder();
1306         sb.append("java.util.Scanner");


1316         sb.append("[negative prefix=" + negativePrefix + "]");
1317         sb.append("[positive suffix=" + positiveSuffix + "]");
1318         sb.append("[negative suffix=" + negativeSuffix + "]");
1319         sb.append("[NaN string=" + nanString + "]");
1320         sb.append("[infinity string=" + infinityString + "]");
1321         return sb.toString();
1322     }
1323 
1324     /**
1325      * Returns true if this scanner has another token in its input.
1326      * This method may block while waiting for input to scan.
1327      * The scanner does not advance past any input.
1328      *
1329      * @return true if and only if this scanner has another token
1330      * @throws IllegalStateException if this scanner is closed
1331      * @see java.util.Iterator
1332      */
1333     public boolean hasNext() {
1334         ensureOpen();
1335         saveState();

1336         while (!sourceClosed) {
1337             if (hasTokenInBuffer())
1338                 return revertState(true);
1339             readInput();
1340         }
1341         boolean result = hasTokenInBuffer();
1342         return revertState(result);
1343     }
1344 
1345     /**
1346      * Finds and returns the next complete token from this scanner.
1347      * A complete token is preceded and followed by input that matches
1348      * the delimiter pattern. This method may block while waiting for input
1349      * to scan, even if a previous invocation of {@link #hasNext} returned
1350      * {@code true}.
1351      *
1352      * @return the next token
1353      * @throws NoSuchElementException if no more tokens are available
1354      * @throws IllegalStateException if this scanner is closed
1355      * @see java.util.Iterator
1356      */
1357     public String next() {
1358         ensureOpen();
1359         clearCaches();

1360 
1361         while (true) {
1362             String token = getCompleteTokenInBuffer(null);
1363             if (token != null) {
1364                 matchValid = true;
1365                 skipped = false;
1366                 return token;
1367             }
1368             if (needInput)
1369                 readInput();
1370             else
1371                 throwFor();
1372         }
1373     }
1374 
1375     /**
1376      * The remove operation is not supported by this implementation of
1377      * {@code Iterator}.
1378      *
1379      * @throws UnsupportedOperationException if this method is invoked.


1418         return next(patternCache.forName(pattern));
1419     }
1420 
1421     /**
1422      * Returns true if the next complete token matches the specified pattern.
1423      * A complete token is prefixed and postfixed by input that matches
1424      * the delimiter pattern. This method may block while waiting for input.
1425      * The scanner does not advance past any input.
1426      *
1427      * @param pattern the pattern to scan for
1428      * @return true if and only if this scanner has another token matching
1429      *         the specified pattern
1430      * @throws IllegalStateException if this scanner is closed
1431      */
1432     public boolean hasNext(Pattern pattern) {
1433         ensureOpen();
1434         if (pattern == null)
1435             throw new NullPointerException();
1436         hasNextPattern = null;
1437         saveState();

1438 
1439         while (true) {
1440             if (getCompleteTokenInBuffer(pattern) != null) {
1441                 matchValid = true;
1442                 cacheResult();
1443                 return revertState(true);
1444             }
1445             if (needInput)
1446                 readInput();
1447             else
1448                 return revertState(false);
1449         }
1450     }
1451 
1452     /**
1453      * Returns the next token if it matches the specified pattern. This
1454      * method may block while waiting for input to scan, even if a previous
1455      * invocation of {@link #hasNext(Pattern)} returned {@code true}.
1456      * If the match is successful, the scanner advances past the input that
1457      * matched the pattern.
1458      *
1459      * @param pattern the pattern to scan for
1460      * @return the next token
1461      * @throws NoSuchElementException if no more tokens are available
1462      * @throws IllegalStateException if this scanner is closed
1463      */
1464     public String next(Pattern pattern) {
1465         ensureOpen();
1466         if (pattern == null)
1467             throw new NullPointerException();
1468 

1469         // Did we already find this pattern?
1470         if (hasNextPattern == pattern)
1471             return getCachedResult();
1472         clearCaches();
1473 
1474         // Search for the pattern
1475         while (true) {
1476             String token = getCompleteTokenInBuffer(pattern);
1477             if (token != null) {
1478                 matchValid = true;
1479                 skipped = false;
1480                 return token;
1481             }
1482             if (needInput)
1483                 readInput();
1484             else
1485                 throwFor();
1486         }
1487     }
1488 
1489     /**
1490      * Returns true if there is another line in the input of this scanner.
1491      * This method may block while waiting for input. The scanner does not
1492      * advance past any input.
1493      *
1494      * @return true if and only if this scanner has another line of input
1495      * @throws IllegalStateException if this scanner is closed
1496      */
1497     public boolean hasNextLine() {
1498         saveState();
1499 

1500         String result = findWithinHorizon(linePattern(), 0);
1501         if (result != null) {
1502             MatchResult mr = this.match();
1503             String lineSep = mr.group(1);
1504             if (lineSep != null) {
1505                 result = result.substring(0, result.length() -
1506                                           lineSep.length());
1507                 cacheResult(result);
1508 
1509             } else {
1510                 cacheResult();
1511             }
1512         }
1513         revertState();
1514         return (result != null);
1515     }
1516 
1517     /**
1518      * Advances this scanner past the current line and returns the input
1519      * that was skipped.
1520      *
1521      * This method returns the rest of the current line, excluding any line
1522      * separator at the end. The position is set to the beginning of the next
1523      * line.
1524      *
1525      * <p>Since this method continues to search through the input looking
1526      * for a line separator, it may buffer all of the input searching for
1527      * the line to skip if no line separators are present.
1528      *
1529      * @return the line that was skipped
1530      * @throws NoSuchElementException if no line was found
1531      * @throws IllegalStateException if this scanner is closed
1532      */
1533     public String nextLine() {

1534         if (hasNextPattern == linePattern())
1535             return getCachedResult();
1536         clearCaches();
1537 
1538         String result = findWithinHorizon(linePattern, 0);
1539         if (result == null)
1540             throw new NoSuchElementException("No line found");
1541         MatchResult mr = this.match();
1542         String lineSep = mr.group(1);
1543         if (lineSep != null)
1544             result = result.substring(0, result.length() - lineSep.length());
1545         if (result == null)
1546             throw new NoSuchElementException();
1547         else
1548             return result;
1549     }
1550 
1551     // Public methods that ignore delimiters
1552 
1553     /**


1572      * scanner advances past the input that matched and returns the string that
1573      * matched the pattern.
1574      * If no such pattern is detected in the input up to the next line
1575      * separator, then {@code null} is returned and the scanner's
1576      * position is unchanged. This method may block waiting for input that
1577      * matches the pattern.
1578      *
1579      * <p>Since this method continues to search through the input looking
1580      * for the specified pattern, it may buffer all of the input searching for
1581      * the desired token if no line separators are present.
1582      *
1583      * @param pattern the pattern to scan for
1584      * @return the text that matched the specified pattern
1585      * @throws IllegalStateException if this scanner is closed
1586      */
1587     public String findInLine(Pattern pattern) {
1588         ensureOpen();
1589         if (pattern == null)
1590             throw new NullPointerException();
1591         clearCaches();

1592         // Expand buffer to include the next newline or end of input
1593         int endPosition = 0;
1594         saveState();
1595         while (true) {
1596             String token = findPatternInBuffer(separatorPattern(), 0);
1597             if (token != null) {
1598                 endPosition = matcher.start();
1599                 break; // up to next newline
1600             }
1601             if (needInput) {
1602                 readInput();
1603             } else {
1604                 endPosition = buf.limit();
1605                 break; // up to end of input
1606             }
1607         }
1608         revertState();
1609         int horizonForLine = endPosition - position;
1610         // If there is nothing between the current pos and the next
1611         // newline simply return null, invoking findWithinHorizon
1612         // with "horizon=0" will scan beyond the line bound.
1613         if (horizonForLine == 0)
1614             return null;
1615         // Search for the pattern
1616         return findWithinHorizon(pattern, horizonForLine);
1617     }
1618 
1619     /**
1620      * Attempts to find the next occurrence of a pattern constructed from the
1621      * specified string, ignoring delimiters.
1622      *
1623      * <p>An invocation of this method of the form
1624      * {@code findWithinHorizon(pattern)} behaves in exactly the same way as
1625      * the invocation
1626      * {@code findWithinHorizon(Pattern.compile(pattern, horizon))}.
1627      *
1628      * @param pattern a string specifying the pattern to search for
1629      * @param horizon the search horizon
1630      * @return the text that matched the specified pattern
1631      * @throws IllegalStateException if this scanner is closed
1632      * @throws IllegalArgumentException if horizon is negative
1633      */
1634     public String findWithinHorizon(String pattern, int horizon) {
1635         return findWithinHorizon(patternCache.forName(pattern), horizon);
1636     }
1637 
1638     /**
1639      * Attempts to find the next occurrence of the specified pattern.
1640      *
1641      * <p>This method searches through the input up to the specified
1642      * search horizon, ignoring delimiters. If the pattern is found the
1643      * scanner advances past the input that matched and returns the string
1644      * that matched the pattern. If no such pattern is detected then the
1645      * null is returned and the scanner's position remains unchanged. This
1646      * method may block waiting for input that matches the pattern.


1656      * this method continues to search through the input looking for the
1657      * specified pattern without bound. In this case it may buffer all of
1658      * the input searching for the pattern.
1659      *
1660      * <p>If horizon is negative, then an IllegalArgumentException is
1661      * thrown.
1662      *
1663      * @param pattern the pattern to scan for
1664      * @param horizon the search horizon
1665      * @return the text that matched the specified pattern
1666      * @throws IllegalStateException if this scanner is closed
1667      * @throws IllegalArgumentException if horizon is negative
1668      */
1669     public String findWithinHorizon(Pattern pattern, int horizon) {
1670         ensureOpen();
1671         if (pattern == null)
1672             throw new NullPointerException();
1673         if (horizon < 0)
1674             throw new IllegalArgumentException("horizon < 0");
1675         clearCaches();

1676 
1677         // Search for the pattern
1678         while (true) {
1679             String token = findPatternInBuffer(pattern, horizon);
1680             if (token != null) {
1681                 matchValid = true;
1682                 return token;
1683             }
1684             if (needInput)
1685                 readInput();
1686             else
1687                 break; // up to end of input
1688         }
1689         return null;
1690     }
1691 
1692     /**
1693      * Skips input that matches the specified pattern, ignoring delimiters.
1694      * This method will skip input if an anchored match of the specified
1695      * pattern succeeds.
1696      *
1697      * <p>If a match to the specified pattern is not found at the
1698      * current position, then no input is skipped and a
1699      * {@code NoSuchElementException} is thrown.
1700      *
1701      * <p>Since this method seeks to match the specified pattern starting at
1702      * the scanner's current position, patterns that can match a lot of
1703      * input (".*", for example) may cause the scanner to buffer a large
1704      * amount of input.
1705      *
1706      * <p>Note that it is possible to skip something without risking a
1707      * {@code NoSuchElementException} by using a pattern that can
1708      * match nothing, e.g., {@code sc.skip("[ \t]*")}.
1709      *
1710      * @param pattern a string specifying the pattern to skip over
1711      * @return this scanner
1712      * @throws NoSuchElementException if the specified pattern is not found
1713      * @throws IllegalStateException if this scanner is closed
1714      */
1715     public Scanner skip(Pattern pattern) {
1716         ensureOpen();
1717         if (pattern == null)
1718             throw new NullPointerException();
1719         clearCaches();

1720 
1721         // Search for the pattern
1722         while (true) {
1723             String token = matchPatternInBuffer(pattern);
1724             if (token != null) {
1725                 matchValid = true;
1726                 position = matcher.end();
1727                 return this;
1728             }
1729             if (needInput)
1730                 readInput();
1731             else
1732                 throw new NoSuchElementException();
1733         }
1734     }
1735 
1736     /**
1737      * Skips input that matches a pattern constructed from the specified
1738      * string.
1739      *
1740      * <p> An invocation of this method of the form {@code skip(pattern)}
1741      * behaves in exactly the same way as the invocation
1742      * {@code skip(Pattern.compile(pattern))}.
1743      *
1744      * @param pattern a string specifying the pattern to skip over


1915         setRadix(radix);
1916         boolean result = hasNext(integerPattern());
1917         if (result) { // Cache it
1918             try {
1919                 String s = (matcher.group(SIMPLE_GROUP_INDEX) == null) ?
1920                     processIntegerToken(hasNextResult) :
1921                     hasNextResult;
1922                 typeCache = Short.parseShort(s, radix);
1923             } catch (NumberFormatException nfe) {
1924                 result = false;
1925             }
1926         }
1927         return result;
1928     }
1929 
1930     /**
1931      * Scans the next token of the input as a {@code short}.
1932      *
1933      * <p> An invocation of this method of the form
1934      * {@code nextShort()} behaves in exactly the same way as the
1935      * invocation {@code nextShort(radix)}, where {@code radix}
1936      * is the default radix of this scanner.
1937      *
1938      * @return the {@code short} scanned from the input
1939      * @throws InputMismatchException
1940      *         if the next token does not match the <i>Integer</i>
1941      *         regular expression, or is out of range
1942      * @throws NoSuchElementException if input is exhausted
1943      * @throws IllegalStateException if this scanner is closed
1944      */
1945     public short nextShort() {
1946         return nextShort(defaultRadix);
1947     }
1948 
1949     /**
1950      * Scans the next token of the input as a {@code short}.
1951      * This method will throw {@code InputMismatchException}
1952      * if the next token cannot be translated into a valid short value as
1953      * described below. If the translation is successful, the scanner advances
1954      * past the input that matched.
1955      *


2573             BigDecimal val = (BigDecimal)typeCache;
2574             useTypeCache();
2575             return val;
2576         }
2577         setRadix(10);
2578         clearCaches();
2579         // Search for next float
2580         try {
2581             String s = processFloatToken(next(decimalPattern()));
2582             return new BigDecimal(s);
2583         } catch (NumberFormatException nfe) {
2584             position = matcher.start(); // don't skip bad token
2585             throw new InputMismatchException(nfe.getMessage());
2586         }
2587     }
2588 
2589     /**
2590      * Resets this scanner.
2591      *
2592      * <p> Resetting a scanner discards all of its explicit state
2593      * information which may have been changed by invocations of {@link
2594      * #useDelimiter}, {@link #useLocale}, or {@link #useRadix}.


2595      *
2596      * <p> An invocation of this method of the form
2597      * {@code scanner.reset()} behaves in exactly the same way as the
2598      * invocation
2599      *
2600      * <blockquote><pre>{@code
2601      *   scanner.useDelimiter("\\p{javaWhitespace}+")
2602      *          .useLocale(Locale.getDefault(Locale.Category.FORMAT))
2603      *          .useRadix(10);
2604      * }</pre></blockquote>
2605      *
2606      * @return this scanner
2607      *
2608      * @since 1.6
2609      */
2610     public Scanner reset() {
2611         delimPattern = WHITESPACE_PATTERN;
2612         useLocale(Locale.getDefault(Locale.Category.FORMAT));
2613         useRadix(10);
2614         clearCaches();

2615         return this;
2616     }







































































































































































































2617 }
   1 /*
   2  * Copyright (c) 2003, 2015, 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
  23  * questions.
  24  */
  25 
  26 package java.util;
  27 



  28 import java.io.*;
  29 import java.math.*;
  30 import java.nio.*;
  31 import java.nio.channels.*;
  32 import java.nio.charset.*;
  33 import java.nio.file.Path;
  34 import java.nio.file.Files;
  35 import java.text.*;
  36 import java.util.function.Consumer;
  37 import java.util.regex.*;
  38 import java.util.stream.Stream;
  39 import java.util.stream.StreamSupport;
  40 
  41 import sun.misc.LRUCache;
  42 
  43 /**
  44  * A simple text scanner which can parse primitive types and strings using
  45  * regular expressions.
  46  *
  47  * <p>A {@code Scanner} breaks its input into tokens using a
  48  * delimiter pattern, which by default matches whitespace. The resulting
  49  * tokens may then be converted into values of different types using the
  50  * various {@code next} methods.
  51  *
  52  * <p>For example, this code allows a user to read a number from
  53  * {@code System.in}:
  54  * <blockquote><pre>{@code
  55  *     Scanner sc = new Scanner(System.in);
  56  *     int i = sc.nextInt();
  57  * }</pre></blockquote>
  58  *
  59  * <p>As another example, this code allows {@code long} types to be


  81  * <blockquote><pre>{@code
  82  *     1
  83  *     2
  84  *     red
  85  *     blue
  86  * }</pre></blockquote>
  87  *
  88  * <p>The same output can be generated with this code, which uses a regular
  89  * expression to parse all four tokens at once:
  90  * <blockquote><pre>{@code
  91  *     String input = "1 fish 2 fish red fish blue fish";
  92  *     Scanner s = new Scanner(input);
  93  *     s.findInLine("(\\d+) fish (\\d+) fish (\\w+) fish (\\w+)");
  94  *     MatchResult result = s.match();
  95  *     for (int i=1; i<=result.groupCount(); i++)
  96  *         System.out.println(result.group(i));
  97  *     s.close();
  98  * }</pre></blockquote>
  99  *
 100  * <p>The <a name="default-delimiter">default whitespace delimiter</a> used
 101  * by a scanner is as recognized by {@link Character#isWhitespace(char)
 102  * Character.isWhitespace()}. The {@link #reset reset()}
 103  * method will reset the value of the scanner's delimiter to the default
 104  * whitespace delimiter regardless of whether it was previously changed.
 105  *
 106  * <p>A scanning operation may block waiting for input.
 107  *
 108  * <p>The {@link #next} and {@link #hasNext} methods and their
 109  * companion methods (such as {@link #nextInt} and
 110  * {@link #hasNextInt}) first skip any input that matches the delimiter
 111  * pattern, and then attempt to return the next token. Both {@code hasNext()}
 112  * and {@code next()} methods may block waiting for further input.  Whether a
 113  * {@code hasNext()} method blocks has no connection to whether or not its
 114  * associated {@code next()} method will block. The {@link #tokens} method
 115  * may also block waiting for input.
 116  *
 117  * <p>The {@link #findInLine findInLine()},
 118  * {@link #findWithinHorizon findWithinHorizon()},
 119  * {@link #skip skip()}, and {@link #findAll findAll()}
 120  * methods operate independently of the delimiter pattern. These methods will
 121  * attempt to match the specified pattern with no regard to delimiters in the
 122  * input and thus can be used in special circumstances where delimiters are
 123  * not relevant. These methods may block waiting for more input.
 124  *
 125  * <p>When a scanner throws an {@link InputMismatchException}, the scanner
 126  * will not pass the token that caused the exception, so that it may be
 127  * retrieved or skipped via some other method.
 128  *
 129  * <p>Depending upon the type of delimiting pattern, empty tokens may be
 130  * returned. For example, the pattern {@code "\\s+"} will return no empty
 131  * tokens since it matches multiple instances of the delimiter. The delimiting
 132  * pattern {@code "\\s"} could return empty tokens since it only passes one
 133  * space at a time.
 134  *
 135  * <p> A scanner can read text from any object which implements the {@link
 136  * java.lang.Readable} interface.  If an invocation of the underlying
 137  * readable's {@link java.lang.Readable#read read()} method throws an {@link
 138  * java.io.IOException} then the scanner assumes that the end of the input
 139  * has been reached.  The most recent {@code IOException} thrown by the
 140  * underlying readable can be retrieved via the {@link #ioException} method.
 141  *
 142  * <p>When a {@code Scanner} is closed, it will close its input source
 143  * if the source implements the {@link java.io.Closeable} interface.
 144  *
 145  * <p>A {@code Scanner} is not safe for multithreaded use without
 146  * external synchronization.
 147  *
 148  * <p>Unless otherwise mentioned, passing a {@code null} parameter into
 149  * any method of a {@code Scanner} will cause a
 150  * {@code NullPointerException} to be thrown.
 151  *
 152  * <p>A scanner will default to interpreting numbers as decimal unless a
 153  * different radix has been set by using the {@link #useRadix} method. The
 154  * {@link #reset} method will reset the value of the scanner's radix to
 155  * {@code 10} regardless of whether it was previously changed.
 156  *
 157  * <h3> <a name="localized-numbers">Localized numbers</a> </h3>
 158  *
 159  * <p> An instance of this class is capable of scanning numbers in the standard
 160  * formats as well as in the formats of the scanner's locale. A scanner's
 161  * <a name="initial-locale">initial locale </a>is the value returned by the {@link
 162  * java.util.Locale#getDefault(Locale.Category)
 163  * Locale.getDefault(Locale.Category.FORMAT)} method; it may be changed via the {@link
 164  * #useLocale useLocale()} method. The {@link #reset} method will reset the value of the
 165  * scanner's locale to the initial locale regardless of whether it was
 166  * previously changed.
 167  *
 168  * <p>The localized formats are defined in terms of the following parameters,
 169  * which for a particular locale are taken from that locale's {@link
 170  * java.text.DecimalFormat DecimalFormat} object, {@code df}, and its and
 171  * {@link java.text.DecimalFormatSymbols DecimalFormatSymbols} object,
 172  * {@code dfs}.
 173  *
 174  * <blockquote><dl>
 175  *     <dt><i>LocalGroupSeparator&nbsp;&nbsp;</i>
 176  *         <dd>The character used to separate thousands groups,
 177  *         <i>i.e.,</i>&nbsp;{@code dfs.}{@link
 178  *         java.text.DecimalFormatSymbols#getGroupingSeparator
 179  *         getGroupingSeparator()}
 180  *     <dt><i>LocalDecimalSeparator&nbsp;&nbsp;</i>
 181  *         <dd>The character used for the decimal point,
 182  *     <i>i.e.,</i>&nbsp;{@code dfs.}{@link
 183  *     java.text.DecimalFormatSymbols#getDecimalSeparator
 184  *     getDecimalSeparator()}


 362     // The default radix for this scanner
 363     private int defaultRadix = 10;
 364 
 365     // The locale used by this scanner
 366     private Locale locale = null;
 367 
 368     // A cache of the last few recently used Patterns
 369     private LRUCache<String,Pattern> patternCache =
 370     new LRUCache<String,Pattern>(7) {
 371         protected Pattern create(String s) {
 372             return Pattern.compile(s);
 373         }
 374         protected boolean hasName(Pattern p, String s) {
 375             return p.pattern().equals(s);
 376         }
 377     };
 378 
 379     // A holder of the last IOException encountered
 380     private IOException lastException;
 381 
 382     // Number of times this scanner's state has been modified.
 383     // Generally incremented on most public APIs and checked
 384     // within spliterator implementations.
 385     int modCount;
 386 
 387     // A pattern for java whitespace
 388     private static Pattern WHITESPACE_PATTERN = Pattern.compile(
 389                                                 "\\p{javaWhitespace}+");
 390 
 391     // A pattern for any token
 392     private static Pattern FIND_ANY_PATTERN = Pattern.compile("(?s).*");
 393 
 394     // A pattern for non-ASCII digits
 395     private static Pattern NON_ASCII_DIGIT = Pattern.compile(
 396         "[\\p{javaDigit}&&[^0-9]]");
 397 
 398     // Fields and methods to support scanning primitive types
 399 
 400     /**
 401      * Locale dependent values used to scan numbers
 402      */
 403     private String groupSeparator = "\\,";
 404     private String decimalSeparator = "\\.";
 405     private String nanString = "NaN";
 406     private String infinityString = "Infinity";


 988             }
 989             // Last token; Match the pattern here or throw
 990             matcher.usePattern(pattern);
 991             matcher.region(position, buf.limit());
 992             if (matcher.matches()) {
 993                 String s = matcher.group();
 994                 position = matcher.end();
 995                 return s;
 996             }
 997             // Last piece does not match
 998             return null;
 999         }
1000 
1001         // There is a partial token in the buffer; must read more
1002         // to complete it
1003         needInput = true;
1004         return null;
1005     }
1006 
1007     // Finds the specified pattern in the buffer up to horizon.
1008     // Returns true if the specified input pattern was matched,
1009     // and leaves the matcher field with the current match state.
1010     private boolean findPatternInBuffer(Pattern pattern, int horizon) {
1011         matchValid = false;
1012         matcher.usePattern(pattern);
1013         int bufferLimit = buf.limit();
1014         int horizonLimit = -1;
1015         int searchLimit = bufferLimit;
1016         if (horizon > 0) {
1017             horizonLimit = position + horizon;
1018             if (horizonLimit < bufferLimit)
1019                 searchLimit = horizonLimit;
1020         }
1021         matcher.region(position, searchLimit);
1022         if (matcher.find()) {
1023             if (matcher.hitEnd() && (!sourceClosed)) {
1024                 // The match may be longer if didn't hit horizon or real end
1025                 if (searchLimit != horizonLimit) {
1026                      // Hit an artificial end; try to extend the match
1027                     needInput = true;
1028                     return false;
1029                 }
1030                 // The match could go away depending on what is next
1031                 if ((searchLimit == horizonLimit) && matcher.requireEnd()) {
1032                     // Rare case: we hit the end of input and it happens
1033                     // that it is at the horizon and the end of input is
1034                     // required for the match.
1035                     needInput = true;
1036                     return false;
1037                 }
1038             }
1039             // Did not hit end, or hit real end, or hit horizon
1040             position = matcher.end();
1041             return true;
1042         }
1043 
1044         if (sourceClosed)
1045             return false;
1046 
1047         // If there is no specified horizon, or if we have not searched
1048         // to the specified horizon yet, get more input
1049         if ((horizon == 0) || (searchLimit != horizonLimit))
1050             needInput = true;
1051         return false;
1052     }
1053 
1054     // Attempts to match a pattern anchored at the current position.
1055     // Returns true if the specified input pattern was matched,
1056     // and leaves the matcher field with the current match state.
1057     private boolean matchPatternInBuffer(Pattern pattern) {
1058         matchValid = false;
1059         matcher.usePattern(pattern);
1060         matcher.region(position, buf.limit());
1061         if (matcher.lookingAt()) {
1062             if (matcher.hitEnd() && (!sourceClosed)) {
1063                 // Get more input and try again
1064                 needInput = true;
1065                 return false;
1066             }
1067             position = matcher.end();
1068             return true;
1069         }
1070 
1071         if (sourceClosed)
1072             return false;
1073 
1074         // Read more to find pattern
1075         needInput = true;
1076         return false;
1077     }
1078 
1079     // Throws if the scanner is closed
1080     private void ensureOpen() {
1081         if (closed)
1082             throw new IllegalStateException("Scanner closed");
1083     }
1084 
1085     // Public methods
1086 
1087     /**
1088      * Closes this scanner.
1089      *
1090      * <p> If this scanner has not yet been closed then if its underlying
1091      * {@linkplain java.lang.Readable readable} also implements the {@link
1092      * java.io.Closeable} interface then the readable's {@code close} method
1093      * will be invoked.  If this scanner is already closed then invoking this
1094      * method will have no effect.
1095      *
1096      * <p>Attempting to perform search operations after a scanner has


1123         return lastException;
1124     }
1125 
1126     /**
1127      * Returns the {@code Pattern} this {@code Scanner} is currently
1128      * using to match delimiters.
1129      *
1130      * @return this scanner's delimiting pattern.
1131      */
1132     public Pattern delimiter() {
1133         return delimPattern;
1134     }
1135 
1136     /**
1137      * Sets this scanner's delimiting pattern to the specified pattern.
1138      *
1139      * @param pattern A delimiting pattern
1140      * @return this scanner
1141      */
1142     public Scanner useDelimiter(Pattern pattern) {
1143         modCount++;
1144         delimPattern = pattern;
1145         return this;
1146     }
1147 
1148     /**
1149      * Sets this scanner's delimiting pattern to a pattern constructed from
1150      * the specified {@code String}.
1151      *
1152      * <p> An invocation of this method of the form
1153      * {@code useDelimiter(pattern)} behaves in exactly the same way as the
1154      * invocation {@code useDelimiter(Pattern.compile(pattern))}.
1155      *
1156      * <p> Invoking the {@link #reset} method will set the scanner's delimiter
1157      * to the <a href= "#default-delimiter">default</a>.
1158      *
1159      * @param pattern A string specifying a delimiting pattern
1160      * @return this scanner
1161      */
1162     public Scanner useDelimiter(String pattern) {
1163         modCount++;
1164         delimPattern = patternCache.forName(pattern);
1165         return this;
1166     }
1167 
1168     /**
1169      * Returns this scanner's locale.
1170      *
1171      * <p>A scanner's locale affects many elements of its default
1172      * primitive matching regular expressions; see
1173      * <a href= "#localized-numbers">localized numbers</a> above.
1174      *
1175      * @return this scanner's locale
1176      */
1177     public Locale locale() {
1178         return this.locale;
1179     }
1180 
1181     /**
1182      * Sets this scanner's locale to the specified locale.
1183      *
1184      * <p>A scanner's locale affects many elements of its default
1185      * primitive matching regular expressions; see
1186      * <a href= "#localized-numbers">localized numbers</a> above.
1187      *
1188      * <p>Invoking the {@link #reset} method will set the scanner's locale to
1189      * the <a href= "#initial-locale">initial locale</a>.
1190      *
1191      * @param locale A string specifying the locale to use
1192      * @return this scanner
1193      */
1194     public Scanner useLocale(Locale locale) {
1195         if (locale.equals(this.locale))
1196             return this;
1197 
1198         modCount++;
1199         this.locale = locale;
1200         DecimalFormat df =
1201             (DecimalFormat)NumberFormat.getNumberInstance(locale);
1202         DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(locale);
1203 
1204         // These must be literalized to avoid collision with regex
1205         // metacharacters such as dot or parenthesis
1206         groupSeparator =   "\\" + dfs.getGroupingSeparator();
1207         decimalSeparator = "\\" + dfs.getDecimalSeparator();
1208 
1209         // Quoting the nonzero length locale-specific things
1210         // to avoid potential conflict with metacharacters
1211         nanString = "\\Q" + dfs.getNaN() + "\\E";
1212         infinityString = "\\Q" + dfs.getInfinity() + "\\E";
1213         positivePrefix = df.getPositivePrefix();
1214         if (positivePrefix.length() > 0)
1215             positivePrefix = "\\Q" + positivePrefix + "\\E";
1216         negativePrefix = df.getNegativePrefix();
1217         if (negativePrefix.length() > 0)
1218             negativePrefix = "\\Q" + negativePrefix + "\\E";


1234     /**
1235      * Returns this scanner's default radix.
1236      *
1237      * <p>A scanner's radix affects elements of its default
1238      * number matching regular expressions; see
1239      * <a href= "#localized-numbers">localized numbers</a> above.
1240      *
1241      * @return the default radix of this scanner
1242      */
1243     public int radix() {
1244         return this.defaultRadix;
1245     }
1246 
1247     /**
1248      * Sets this scanner's default radix to the specified radix.
1249      *
1250      * <p>A scanner's radix affects elements of its default
1251      * number matching regular expressions; see
1252      * <a href= "#localized-numbers">localized numbers</a> above.
1253      *
1254      * <p>If the radix is less than {@link Character#MIN_RADIX Character.MIN_RADIX}
1255      * or greater than {@link Character#MAX_RADIX Character.MAX_RADIX}, then an
1256      * {@code IllegalArgumentException} is thrown.
1257      *
1258      * <p>Invoking the {@link #reset} method will set the scanner's radix to
1259      * {@code 10}.
1260      *
1261      * @param radix The radix to use when scanning numbers
1262      * @return this scanner
1263      * @throws IllegalArgumentException if radix is out of range
1264      */
1265     public Scanner useRadix(int radix) {
1266         if ((radix < Character.MIN_RADIX) || (radix > Character.MAX_RADIX))
1267             throw new IllegalArgumentException("radix:"+radix);
1268 
1269         if (this.defaultRadix == radix)
1270             return this;
1271         modCount++;
1272         this.defaultRadix = radix;
1273         // Force rebuilding and recompilation of radix dependent patterns
1274         integerPattern = null;
1275         return this;
1276     }
1277 
1278     // The next operation should occur in the specified radix but
1279     // the default is left untouched.
1280     private void setRadix(int radix) {
1281         if (this.radix != radix) {
1282             // Force rebuilding and recompilation of radix dependent patterns
1283             integerPattern = null;
1284             this.radix = radix;
1285         }
1286     }
1287 
1288     /**
1289      * Returns the match result of the last scanning operation performed
1290      * by this scanner. This method throws {@code IllegalStateException}
1291      * if no match has been performed, or if the last match was
1292      * not successful.
1293      *
1294      * <p>The various {@code next} methods of {@code Scanner}
1295      * make a match result available if they complete without throwing an
1296      * exception. For instance, after an invocation of the {@link #nextInt}
1297      * method that returned an int, this method returns a
1298      * {@code MatchResult} for the search of the
1299      * <a href="#Integer-regex"><i>Integer</i></a> regular expression
1300      * defined above. Similarly the {@link #findInLine findInLine()},
1301      * {@link #findWithinHorizon findWithinHorizon()}, and {@link #skip skip()}
1302      * methods will make a match available if they succeed.
1303      *
1304      * @return a match result for the last match operation
1305      * @throws IllegalStateException  If no match result is available
1306      */
1307     public MatchResult match() {
1308         if (!matchValid)
1309             throw new IllegalStateException("No match result available");
1310         return matcher.toMatchResult();
1311     }
1312 
1313     /**
1314      * <p>Returns the string representation of this {@code Scanner}. The
1315      * string representation of a {@code Scanner} contains information
1316      * that may be useful for debugging. The exact format is unspecified.
1317      *
1318      * @return  The string representation of this scanner
1319      */
1320     public String toString() {
1321         StringBuilder sb = new StringBuilder();
1322         sb.append("java.util.Scanner");


1332         sb.append("[negative prefix=" + negativePrefix + "]");
1333         sb.append("[positive suffix=" + positiveSuffix + "]");
1334         sb.append("[negative suffix=" + negativeSuffix + "]");
1335         sb.append("[NaN string=" + nanString + "]");
1336         sb.append("[infinity string=" + infinityString + "]");
1337         return sb.toString();
1338     }
1339 
1340     /**
1341      * Returns true if this scanner has another token in its input.
1342      * This method may block while waiting for input to scan.
1343      * The scanner does not advance past any input.
1344      *
1345      * @return true if and only if this scanner has another token
1346      * @throws IllegalStateException if this scanner is closed
1347      * @see java.util.Iterator
1348      */
1349     public boolean hasNext() {
1350         ensureOpen();
1351         saveState();
1352         modCount++;
1353         while (!sourceClosed) {
1354             if (hasTokenInBuffer())
1355                 return revertState(true);
1356             readInput();
1357         }
1358         boolean result = hasTokenInBuffer();
1359         return revertState(result);
1360     }
1361 
1362     /**
1363      * Finds and returns the next complete token from this scanner.
1364      * A complete token is preceded and followed by input that matches
1365      * the delimiter pattern. This method may block while waiting for input
1366      * to scan, even if a previous invocation of {@link #hasNext} returned
1367      * {@code true}.
1368      *
1369      * @return the next token
1370      * @throws NoSuchElementException if no more tokens are available
1371      * @throws IllegalStateException if this scanner is closed
1372      * @see java.util.Iterator
1373      */
1374     public String next() {
1375         ensureOpen();
1376         clearCaches();
1377         modCount++;
1378 
1379         while (true) {
1380             String token = getCompleteTokenInBuffer(null);
1381             if (token != null) {
1382                 matchValid = true;
1383                 skipped = false;
1384                 return token;
1385             }
1386             if (needInput)
1387                 readInput();
1388             else
1389                 throwFor();
1390         }
1391     }
1392 
1393     /**
1394      * The remove operation is not supported by this implementation of
1395      * {@code Iterator}.
1396      *
1397      * @throws UnsupportedOperationException if this method is invoked.


1436         return next(patternCache.forName(pattern));
1437     }
1438 
1439     /**
1440      * Returns true if the next complete token matches the specified pattern.
1441      * A complete token is prefixed and postfixed by input that matches
1442      * the delimiter pattern. This method may block while waiting for input.
1443      * The scanner does not advance past any input.
1444      *
1445      * @param pattern the pattern to scan for
1446      * @return true if and only if this scanner has another token matching
1447      *         the specified pattern
1448      * @throws IllegalStateException if this scanner is closed
1449      */
1450     public boolean hasNext(Pattern pattern) {
1451         ensureOpen();
1452         if (pattern == null)
1453             throw new NullPointerException();
1454         hasNextPattern = null;
1455         saveState();
1456         modCount++;
1457 
1458         while (true) {
1459             if (getCompleteTokenInBuffer(pattern) != null) {
1460                 matchValid = true;
1461                 cacheResult();
1462                 return revertState(true);
1463             }
1464             if (needInput)
1465                 readInput();
1466             else
1467                 return revertState(false);
1468         }
1469     }
1470 
1471     /**
1472      * Returns the next token if it matches the specified pattern. This
1473      * method may block while waiting for input to scan, even if a previous
1474      * invocation of {@link #hasNext(Pattern)} returned {@code true}.
1475      * If the match is successful, the scanner advances past the input that
1476      * matched the pattern.
1477      *
1478      * @param pattern the pattern to scan for
1479      * @return the next token
1480      * @throws NoSuchElementException if no more tokens are available
1481      * @throws IllegalStateException if this scanner is closed
1482      */
1483     public String next(Pattern pattern) {
1484         ensureOpen();
1485         if (pattern == null)
1486             throw new NullPointerException();
1487 
1488         modCount++;
1489         // Did we already find this pattern?
1490         if (hasNextPattern == pattern)
1491             return getCachedResult();
1492         clearCaches();
1493 
1494         // Search for the pattern
1495         while (true) {
1496             String token = getCompleteTokenInBuffer(pattern);
1497             if (token != null) {
1498                 matchValid = true;
1499                 skipped = false;
1500                 return token;
1501             }
1502             if (needInput)
1503                 readInput();
1504             else
1505                 throwFor();
1506         }
1507     }
1508 
1509     /**
1510      * Returns true if there is another line in the input of this scanner.
1511      * This method may block while waiting for input. The scanner does not
1512      * advance past any input.
1513      *
1514      * @return true if and only if this scanner has another line of input
1515      * @throws IllegalStateException if this scanner is closed
1516      */
1517     public boolean hasNextLine() {
1518         saveState();
1519 
1520         modCount++;
1521         String result = findWithinHorizon(linePattern(), 0);
1522         if (result != null) {
1523             MatchResult mr = this.match();
1524             String lineSep = mr.group(1);
1525             if (lineSep != null) {
1526                 result = result.substring(0, result.length() -
1527                                           lineSep.length());
1528                 cacheResult(result);
1529 
1530             } else {
1531                 cacheResult();
1532             }
1533         }
1534         revertState();
1535         return (result != null);
1536     }
1537 
1538     /**
1539      * Advances this scanner past the current line and returns the input
1540      * that was skipped.
1541      *
1542      * This method returns the rest of the current line, excluding any line
1543      * separator at the end. The position is set to the beginning of the next
1544      * line.
1545      *
1546      * <p>Since this method continues to search through the input looking
1547      * for a line separator, it may buffer all of the input searching for
1548      * the line to skip if no line separators are present.
1549      *
1550      * @return the line that was skipped
1551      * @throws NoSuchElementException if no line was found
1552      * @throws IllegalStateException if this scanner is closed
1553      */
1554     public String nextLine() {
1555         modCount++;
1556         if (hasNextPattern == linePattern())
1557             return getCachedResult();
1558         clearCaches();
1559 
1560         String result = findWithinHorizon(linePattern, 0);
1561         if (result == null)
1562             throw new NoSuchElementException("No line found");
1563         MatchResult mr = this.match();
1564         String lineSep = mr.group(1);
1565         if (lineSep != null)
1566             result = result.substring(0, result.length() - lineSep.length());
1567         if (result == null)
1568             throw new NoSuchElementException();
1569         else
1570             return result;
1571     }
1572 
1573     // Public methods that ignore delimiters
1574 
1575     /**


1594      * scanner advances past the input that matched and returns the string that
1595      * matched the pattern.
1596      * If no such pattern is detected in the input up to the next line
1597      * separator, then {@code null} is returned and the scanner's
1598      * position is unchanged. This method may block waiting for input that
1599      * matches the pattern.
1600      *
1601      * <p>Since this method continues to search through the input looking
1602      * for the specified pattern, it may buffer all of the input searching for
1603      * the desired token if no line separators are present.
1604      *
1605      * @param pattern the pattern to scan for
1606      * @return the text that matched the specified pattern
1607      * @throws IllegalStateException if this scanner is closed
1608      */
1609     public String findInLine(Pattern pattern) {
1610         ensureOpen();
1611         if (pattern == null)
1612             throw new NullPointerException();
1613         clearCaches();
1614         modCount++;
1615         // Expand buffer to include the next newline or end of input
1616         int endPosition = 0;
1617         saveState();
1618         while (true) {
1619             if (findPatternInBuffer(separatorPattern(), 0)) {

1620                 endPosition = matcher.start();
1621                 break; // up to next newline
1622             }
1623             if (needInput) {
1624                 readInput();
1625             } else {
1626                 endPosition = buf.limit();
1627                 break; // up to end of input
1628             }
1629         }
1630         revertState();
1631         int horizonForLine = endPosition - position;
1632         // If there is nothing between the current pos and the next
1633         // newline simply return null, invoking findWithinHorizon
1634         // with "horizon=0" will scan beyond the line bound.
1635         if (horizonForLine == 0)
1636             return null;
1637         // Search for the pattern
1638         return findWithinHorizon(pattern, horizonForLine);
1639     }
1640 
1641     /**
1642      * Attempts to find the next occurrence of a pattern constructed from the
1643      * specified string, ignoring delimiters.
1644      *
1645      * <p>An invocation of this method of the form
1646      * {@code findWithinHorizon(pattern)} behaves in exactly the same way as
1647      * the invocation
1648      * {@code findWithinHorizon(Pattern.compile(pattern), horizon)}.
1649      *
1650      * @param pattern a string specifying the pattern to search for
1651      * @param horizon the search horizon
1652      * @return the text that matched the specified pattern
1653      * @throws IllegalStateException if this scanner is closed
1654      * @throws IllegalArgumentException if horizon is negative
1655      */
1656     public String findWithinHorizon(String pattern, int horizon) {
1657         return findWithinHorizon(patternCache.forName(pattern), horizon);
1658     }
1659 
1660     /**
1661      * Attempts to find the next occurrence of the specified pattern.
1662      *
1663      * <p>This method searches through the input up to the specified
1664      * search horizon, ignoring delimiters. If the pattern is found the
1665      * scanner advances past the input that matched and returns the string
1666      * that matched the pattern. If no such pattern is detected then the
1667      * null is returned and the scanner's position remains unchanged. This
1668      * method may block waiting for input that matches the pattern.


1678      * this method continues to search through the input looking for the
1679      * specified pattern without bound. In this case it may buffer all of
1680      * the input searching for the pattern.
1681      *
1682      * <p>If horizon is negative, then an IllegalArgumentException is
1683      * thrown.
1684      *
1685      * @param pattern the pattern to scan for
1686      * @param horizon the search horizon
1687      * @return the text that matched the specified pattern
1688      * @throws IllegalStateException if this scanner is closed
1689      * @throws IllegalArgumentException if horizon is negative
1690      */
1691     public String findWithinHorizon(Pattern pattern, int horizon) {
1692         ensureOpen();
1693         if (pattern == null)
1694             throw new NullPointerException();
1695         if (horizon < 0)
1696             throw new IllegalArgumentException("horizon < 0");
1697         clearCaches();
1698         modCount++;
1699 
1700         // Search for the pattern
1701         while (true) {
1702             if (findPatternInBuffer(pattern, horizon)) {

1703                 matchValid = true;
1704                 return matcher.group();
1705             }
1706             if (needInput)
1707                 readInput();
1708             else
1709                 break; // up to end of input
1710         }
1711         return null;
1712     }
1713 
1714     /**
1715      * Skips input that matches the specified pattern, ignoring delimiters.
1716      * This method will skip input if an anchored match of the specified
1717      * pattern succeeds.
1718      *
1719      * <p>If a match to the specified pattern is not found at the
1720      * current position, then no input is skipped and a
1721      * {@code NoSuchElementException} is thrown.
1722      *
1723      * <p>Since this method seeks to match the specified pattern starting at
1724      * the scanner's current position, patterns that can match a lot of
1725      * input (".*", for example) may cause the scanner to buffer a large
1726      * amount of input.
1727      *
1728      * <p>Note that it is possible to skip something without risking a
1729      * {@code NoSuchElementException} by using a pattern that can
1730      * match nothing, e.g., {@code sc.skip("[ \t]*")}.
1731      *
1732      * @param pattern a string specifying the pattern to skip over
1733      * @return this scanner
1734      * @throws NoSuchElementException if the specified pattern is not found
1735      * @throws IllegalStateException if this scanner is closed
1736      */
1737     public Scanner skip(Pattern pattern) {
1738         ensureOpen();
1739         if (pattern == null)
1740             throw new NullPointerException();
1741         clearCaches();
1742         modCount++;
1743 
1744         // Search for the pattern
1745         while (true) {
1746             if (matchPatternInBuffer(pattern)) {

1747                 matchValid = true;
1748                 position = matcher.end();
1749                 return this;
1750             }
1751             if (needInput)
1752                 readInput();
1753             else
1754                 throw new NoSuchElementException();
1755         }
1756     }
1757 
1758     /**
1759      * Skips input that matches a pattern constructed from the specified
1760      * string.
1761      *
1762      * <p> An invocation of this method of the form {@code skip(pattern)}
1763      * behaves in exactly the same way as the invocation
1764      * {@code skip(Pattern.compile(pattern))}.
1765      *
1766      * @param pattern a string specifying the pattern to skip over


1937         setRadix(radix);
1938         boolean result = hasNext(integerPattern());
1939         if (result) { // Cache it
1940             try {
1941                 String s = (matcher.group(SIMPLE_GROUP_INDEX) == null) ?
1942                     processIntegerToken(hasNextResult) :
1943                     hasNextResult;
1944                 typeCache = Short.parseShort(s, radix);
1945             } catch (NumberFormatException nfe) {
1946                 result = false;
1947             }
1948         }
1949         return result;
1950     }
1951 
1952     /**
1953      * Scans the next token of the input as a {@code short}.
1954      *
1955      * <p> An invocation of this method of the form
1956      * {@code nextShort()} behaves in exactly the same way as the
1957      * invocation {@link #nextShort(int) nextShort(radix)}, where {@code radix}
1958      * is the default radix of this scanner.
1959      *
1960      * @return the {@code short} scanned from the input
1961      * @throws InputMismatchException
1962      *         if the next token does not match the <i>Integer</i>
1963      *         regular expression, or is out of range
1964      * @throws NoSuchElementException if input is exhausted
1965      * @throws IllegalStateException if this scanner is closed
1966      */
1967     public short nextShort() {
1968         return nextShort(defaultRadix);
1969     }
1970 
1971     /**
1972      * Scans the next token of the input as a {@code short}.
1973      * This method will throw {@code InputMismatchException}
1974      * if the next token cannot be translated into a valid short value as
1975      * described below. If the translation is successful, the scanner advances
1976      * past the input that matched.
1977      *


2595             BigDecimal val = (BigDecimal)typeCache;
2596             useTypeCache();
2597             return val;
2598         }
2599         setRadix(10);
2600         clearCaches();
2601         // Search for next float
2602         try {
2603             String s = processFloatToken(next(decimalPattern()));
2604             return new BigDecimal(s);
2605         } catch (NumberFormatException nfe) {
2606             position = matcher.start(); // don't skip bad token
2607             throw new InputMismatchException(nfe.getMessage());
2608         }
2609     }
2610 
2611     /**
2612      * Resets this scanner.
2613      *
2614      * <p> Resetting a scanner discards all of its explicit state
2615      * information which may have been changed by invocations of
2616      * {@link #useDelimiter useDelimiter()},
2617      * {@link #useLocale useLocale()}, or
2618      * {@link #useRadix useRadix()}.
2619      *
2620      * <p> An invocation of this method of the form
2621      * {@code scanner.reset()} behaves in exactly the same way as the
2622      * invocation
2623      *
2624      * <blockquote><pre>{@code
2625      *   scanner.useDelimiter("\\p{javaWhitespace}+")
2626      *          .useLocale(Locale.getDefault(Locale.Category.FORMAT))
2627      *          .useRadix(10);
2628      * }</pre></blockquote>
2629      *
2630      * @return this scanner
2631      *
2632      * @since 1.6
2633      */
2634     public Scanner reset() {
2635         delimPattern = WHITESPACE_PATTERN;
2636         useLocale(Locale.getDefault(Locale.Category.FORMAT));
2637         useRadix(10);
2638         clearCaches();
2639         modCount++;
2640         return this;
2641     }
2642 
2643     /**
2644      * Returns a stream of delimiter-separated tokens from this scanner. The
2645      * stream contains the same tokens that would be returned, starting from
2646      * this scanner's current state, by calling the {@link #next} method
2647      * repeatedly until the {@link #hasNext} method returns false.
2648      *
2649      * <p>The resulting stream is sequential and ordered. All stream elements are
2650      * non-null.
2651      *
2652      * <p>Scanning starts upon initiation of the terminal stream operation, using the
2653      * current state of this scanner. Subsequent calls to any methods on this scanner
2654      * other than {@link #close} and {@link #ioException} may return undefined results
2655      * or may cause undefined effects on the returned stream. The returned stream's source
2656      * {@code Spliterator} is <em>fail-fast</em> and will, on a best-effort basis, throw a
2657      * {@link java.util.ConcurrentModificationException} if any such calls are detected
2658      * during stream pipeline execution.
2659      *
2660      * <p>After stream pipeline execution completes, this scanner is left in an indeterminate
2661      * state and cannot be reused.
2662      *
2663      * <p>If this scanner contains a resource that must be released, this scanner
2664      * should be closed, either by calling its {@link #close} method, or by
2665      * closing the returned stream. Closing the stream will close the underlying scanner.
2666      * {@code IllegalStateException} is thrown if the scanner has been closed when this
2667      * method is called, or if this scanner is closed during stream pipeline execution.
2668      *
2669      * <p>This method might block waiting for more input.
2670      *
2671      * @apiNote
2672      * For example, the following code will create a list of
2673      * comma-delimited tokens from a string:
2674      *
2675      * <pre>{@code
2676      * List<String> result = new Scanner("abc,def,,ghi")
2677      *     .useDelimiter(",")
2678      *     .tokens()
2679      *     .collect(Collectors.toList());
2680      * }</pre>
2681      *
2682      * <p>The resulting list would contain {@code "abc"}, {@code "def"},
2683      * the empty string, and {@code "ghi"}.
2684      *
2685      * @return a sequential stream of token strings
2686      * @throws IllegalStateException if this scanner is closed
2687      * @since 1.9
2688      */
2689     public Stream<String> tokens() {
2690         ensureOpen();
2691         Stream<String> stream = StreamSupport.stream(new TokenSpliterator(), false);
2692         return stream.onClose(this::close);
2693     }
2694 
2695     class TokenSpliterator extends Spliterators.AbstractSpliterator<String> {
2696         int expectedCount = -1;
2697 
2698         TokenSpliterator() {
2699             super(Long.MAX_VALUE,
2700                   Spliterator.IMMUTABLE | Spliterator.NONNULL | Spliterator.ORDERED);
2701         }
2702 
2703         @Override
2704         public boolean tryAdvance(Consumer<? super String> cons) {
2705             if (expectedCount >= 0 && expectedCount != modCount) {
2706                 throw new ConcurrentModificationException();
2707             }
2708 
2709             if (hasNext()) {
2710                 String token = next();
2711                 expectedCount = modCount;
2712                 cons.accept(token);
2713                 if (expectedCount != modCount) {
2714                     throw new ConcurrentModificationException();
2715                 }
2716                 return true;
2717             } else {
2718                 expectedCount = modCount;
2719                 return false;
2720             }
2721         }
2722     }
2723 
2724     /**
2725      * Returns a stream of match results from this scanner. The stream
2726      * contains the same results in the same order that would be returned by
2727      * calling {@code findWithinHorizon(pattern, 0)} and then {@link #match}
2728      * successively as long as {@link #findWithinHorizon findWithinHorizon()}
2729      * finds matches.
2730      *
2731      * <p>The resulting stream is sequential and ordered. All stream elements are
2732      * non-null.
2733      *
2734      * <p>Scanning starts upon initiation of the terminal stream operation, using the
2735      * current state of this scanner. Subsequent calls to any methods on this scanner
2736      * other than {@link #close} and {@link #ioException} may return undefined results
2737      * or may cause undefined effects on the returned stream. The returned stream's source
2738      * {@code Spliterator} is <em>fail-fast</em> and will, on a best-effort basis, throw a
2739      * {@link java.util.ConcurrentModificationException} if any such calls are detected
2740      * during stream pipeline execution.
2741      *
2742      * <p>After stream pipeline execution completes, this scanner is left in an indeterminate
2743      * state and cannot be reused.
2744      *
2745      * <p>If this scanner contains a resource that must be released, this scanner
2746      * should be closed, either by calling its {@link #close} method, or by
2747      * closing the returned stream. Closing the stream will close the underlying scanner.
2748      * {@code IllegalStateException} is thrown if the scanner has been closed when this
2749      * method is called, or if this scanner is closed during stream pipeline execution.
2750      *
2751      * <p>As with the {@link #findWithinHorizon findWithinHorizon()} methods, this method
2752      * might block waiting for additional input, and it might buffer an unbounded amount of
2753      * input searching for a match.
2754      *
2755      * @apiNote
2756      * For example, the following code will read a file and return a list
2757      * of all sequences of characters consisting of seven or more Latin capital
2758      * letters:
2759      *
2760      * <pre>{@code
2761      * try (Scanner sc = new Scanner(Paths.get("input.txt"))) {
2762      *     Pattern pat = Pattern.compile("[A-Z]{7,}");
2763      *     List<String> capWords = sc.findAll(pat)
2764      *                               .map(MatchResult::group)
2765      *                               .collect(Collectors.toList());
2766      * }
2767      * }</pre>
2768      *
2769      * @param pattern the pattern to be matched
2770      * @return a sequential stream of match results
2771      * @throws NullPointerException if pattern is null
2772      * @throws IllegalStateException if this scanner is closed
2773      * @since 1.9
2774      */
2775     public Stream<MatchResult> findAll(Pattern pattern) {
2776         Objects.requireNonNull(pattern);
2777         ensureOpen();
2778         Stream<MatchResult> stream = StreamSupport.stream(new FindSpliterator(pattern), false);
2779         return stream.onClose(this::close);
2780     }
2781 
2782     /**
2783      * Returns a stream of match results that match the provided pattern string.
2784      * The effect is equivalent to the following code:
2785      *
2786      * <pre>{@code
2787      *     scanner.findAll(Pattern.compile(patString))
2788      * }</pre>
2789      *
2790      * @param patString the pattern string
2791      * @return a sequential stream of match results
2792      * @throws NullPointerException if patString is null
2793      * @throws IllegalStateException if this scanner is closed
2794      * @throws PatternSyntaxException if the regular expression's syntax is invalid
2795      * @since 1.9
2796      * @see java.util.regex.Pattern
2797      */
2798     public Stream<MatchResult> findAll(String patString) {
2799         Objects.requireNonNull(patString);
2800         ensureOpen();
2801         return findAll(patternCache.forName(patString));
2802     }
2803 
2804     class FindSpliterator extends Spliterators.AbstractSpliterator<MatchResult> {
2805         final Pattern pattern;
2806         int expectedCount = -1;
2807 
2808         FindSpliterator(Pattern pattern) {
2809             super(Long.MAX_VALUE,
2810                   Spliterator.IMMUTABLE | Spliterator.NONNULL | Spliterator.ORDERED);
2811             this.pattern = pattern;
2812         }
2813 
2814         @Override
2815         public boolean tryAdvance(Consumer<? super MatchResult> cons) {
2816             ensureOpen();
2817             if (expectedCount >= 0) {
2818                 if (expectedCount != modCount) {
2819                     throw new ConcurrentModificationException();
2820                 }
2821             } else {
2822                 expectedCount = modCount;
2823             }
2824 
2825             while (true) {
2826                 // assert expectedCount == modCount
2827                 if (findPatternInBuffer(pattern, 0)) { // doesn't increment modCount
2828                     cons.accept(matcher.toMatchResult());
2829                     if (expectedCount != modCount) {
2830                         throw new ConcurrentModificationException();
2831                     }
2832                     return true;
2833                 }
2834                 if (needInput)
2835                     readInput(); // doesn't increment modCount
2836                 else
2837                     return false; // reached end of input
2838             }
2839         }
2840     }
2841 }
< prev index next >