“扫描程序”的名称有点误导,因为该词通常用于表示词法分析器,而这并不是Scanner的意思。所有这些都可以替代
scanf()您在C,Perl 等人中
找到的功能。像StringTokenizer和一样
split(),它被设计为向前扫描,直到找到与给定模式的匹配为止,然后跳过的任何内容都将作为令牌返回。
另一方面,词法分析器必须检查和分类每个字符,即使只是为了确定是否可以安全地忽略它们也是如此。这意味着,在每次匹配之后,它可能会应用多种模式,直到找到
从该点开始 匹配的模式。否则,它可能会发现序列“ //”,并认为它已找到注释的开始,这时它确实位于字符串文字中,而只是没有注意到开头的引号。
当然,它实际上要比这复杂得多,但是我只是在说明为什么诸如StringTokenizer
split()和Scanner之类的内置工具不适合此类任务。但是,可以将Java的regex类用于有限形式的词法分析。实际上,由于添加了新的Matcher
API来支持Scanner类(即区域和
usePattern()方法),因此添加了Scanner类变得更加容易。这是在Java的regex类之上构建的基本扫描器的示例。
import java.util.*;import java.util.regex.*;public class RETokenizer{ static List<Token> tokenize(String source, List<Rule> rules) { List<Token> tokens = new ArrayList<Token>(); int pos = 0; final int end = source.length(); Matcher m = Pattern.compile("dummy").matcher(source); m.useTransparentBounds(true).useAnchoringBounds(false); while (pos < end) { m.region(pos, end); for (Rule r : rules) { if (m.usePattern(r.pattern).lookingAt()) { tokens.add(new Token(r.name, m.start(), m.end())); pos = m.end(); break; } } pos++; // bump-along, in case no rule matched } return tokens; } static class Rule { final String name; final Pattern pattern; Rule(String name, String regex) { this.name = name; pattern = Pattern.compile(regex); } } static class Token { final String name; final int startPos; final int endPos; Token(String name, int startPos, int endPos) { this.name = name; this.startPos = startPos; this.endPos = endPos; } @Override public String toString() { return String.format("Token [%2d, %2d, %s]", startPos, endPos, name); } } public static void main(String[] args) throws Exception { List<Rule> rules = new ArrayList<Rule>(); rules.add(new Rule("WORD", "[A-Za-z]+")); rules.add(new Rule("QUOTED", ""[^"]*+"")); rules.add(new Rule("COMMENT", "//.*")); rules.add(new Rule("WHITESPACE", "\s+")); String str = "foo //in "comment"nbar "no //comment" end"; List<Token> result = RETokenizer.tokenize(str, rules); for (Token t : result) { System.out.println(t); } }}顺便说一句,这是我所发现的唯一对
lookingAt()方法有用的方法。:D



