< prev index next >

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

Print this page




   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</code> 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 <tt>next</tt> methods.
  49  *
  50  * <p>For example, this code allows a user to read a number from
  51  * <tt>System.in</tt>:
  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</code> types to be


 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 <tt>close</tt> 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


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     }


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      * <tt>NoSuchElementException</tt> 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</code> by using a pattern that can
1708      * match nothing, e.g., <code>sc.skip("[ \t]*")</code>.
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 <tt>skip(pattern)</tt>
1741      * behaves in exactly the same way as the invocation
1742      * <tt>skip(Pattern.compile(pattern))</tt>.
1743      *
1744      * @param pattern a string specifying the pattern to skip over




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


 977             }
 978             // Last token; Match the pattern here or throw
 979             matcher.usePattern(pattern);
 980             matcher.region(position, buf.limit());
 981             if (matcher.matches()) {
 982                 String s = matcher.group();
 983                 position = matcher.end();
 984                 return s;
 985             }
 986             // Last piece does not match
 987             return null;
 988         }
 989 
 990         // There is a partial token in the buffer; must read more
 991         // to complete it
 992         needInput = true;
 993         return null;
 994     }
 995 
 996     // Finds the specified pattern in the buffer up to horizon.
 997     // Returns true if the specified input pattern was matched,
 998     // and leaves the matcher field with the current match state.
 999     private boolean 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 false;
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 false;
1026                 }
1027             }
1028             // Did not hit end, or hit real end, or hit horizon
1029             position = matcher.end();
1030             return true;
1031         }
1032 
1033         if (sourceClosed)
1034             return false;
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 false;
1041     }
1042 
1043     // Attempts to match a pattern anchored at the current position.
1044     // Returns true if the specified input pattern was matched,
1045     // and leaves the matcher field with the current match state.
1046     private boolean matchPatternInBuffer(Pattern pattern) {
1047         matchValid = false;
1048         matcher.usePattern(pattern);
1049         matcher.region(position, buf.limit());
1050         if (matcher.lookingAt()) {
1051             if (matcher.hitEnd() && (!sourceClosed)) {
1052                 // Get more input and try again
1053                 needInput = true;
1054                 return false;
1055             }
1056             position = matcher.end();
1057             return true;
1058         }
1059 
1060         if (sourceClosed)
1061             return false;
1062 
1063         // Read more to find pattern
1064         needInput = true;
1065         return false;
1066     }
1067 
1068     // Throws if the scanner is closed
1069     private void ensureOpen() {
1070         if (closed)
1071             throw new IllegalStateException("Scanner closed");
1072     }
1073 
1074     // Public methods
1075 
1076     /**
1077      * Closes this scanner.
1078      *
1079      * <p> If this scanner has not yet been closed then if its underlying
1080      * {@linkplain java.lang.Readable readable} also implements the {@link
1081      * java.io.Closeable} interface then the readable's <tt>close</tt> method
1082      * will be invoked.  If this scanner is already closed then invoking this
1083      * method will have no effect.
1084      *
1085      * <p>Attempting to perform search operations after a scanner has


1577      * position is unchanged. This method may block waiting for input that
1578      * matches the pattern.
1579      *
1580      * <p>Since this method continues to search through the input looking
1581      * for the specified pattern, it may buffer all of the input searching for
1582      * the desired token if no line separators are present.
1583      *
1584      * @param pattern the pattern to scan for
1585      * @return the text that matched the specified pattern
1586      * @throws IllegalStateException if this scanner is closed
1587      */
1588     public String findInLine(Pattern pattern) {
1589         ensureOpen();
1590         if (pattern == null)
1591             throw new NullPointerException();
1592         clearCaches();
1593         // Expand buffer to include the next newline or end of input
1594         int endPosition = 0;
1595         saveState();
1596         while (true) {
1597             if (findPatternInBuffer(separatorPattern(), 0)) {

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     }


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             if (findPatternInBuffer(pattern, horizon)) {

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

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


< prev index next >