其实我有以下正则表达式令牌(学校职责):
Identificator = [a-zA-Z_][a-zA-Z0-9_]*
Integer = [0-9]+
ReservedKeywords = true|false|while|foreach|for|plus
Symbols = *|/|-|\(|\)|
Blank = \s+
我无法使用Scanner类,因为某些令牌之间可能没有空格。请注意,Parser(给定它接收正确的令牌)已准备好,并且还要进行类型检查和AST评估。只有最简单的"部分缺失所以" Tokenizer"互联网上没有足够的完整示例。
我不了解util.regex.Matcher类的文档,这非常令人困惑。
实际上是合法的
我们必须使用Matcher类,所以无论如何都没有机会对tokenizer进行硬编码(这太简单了:简单的状态机+地图查找,但我们不允许这样做。)
标记器必须有2个方法(" hasNext"" next")。
我需要一些示例来了解如何使用Matcher将字符串与依赖于上下文的分隔符匹配(Scanner类不适合,因为将" eat"分隔符,而分隔符是语法的一部分见下面的例子:
(3 plus 5)*(8/3*7)
它应该被标记为
(.3.plus.5.).*.(.8./.3.*.7.)
我可以使用"(|)| \ s +"作为分隔符,但扫描仪将返回
3 plus 5 * 8 / 3 * 7
由于运营商的关联性,结果将是
3 plus (((5*8)/3)*7)
这是不正确的。
我需要做以下事情:
给定一组模式(Identificator,Integer,ReservedKeywords,Symbols,Blank等等)。我需要匹配任何这些模式的第一次出现。分隔符是"符号|空白" 但是不应该丢弃分隔符,而应该将它们作为代币返回。 这必须使用Matcher类完成。
一个示例,说明如何使用as分隔符标记字符串" Blank |符号"返回或分隔的字符串或分隔符本身就足够了。
答案 0 :(得分:0)
在花了很多时间弄清楚Matcher是如何工作之后,我能够创建一个比通常的Scanner更复杂的标记器。由于没有人回答这是相关部分(因为这是学校作业,我可以分享代码):
private final Scanner scanner;
private final String delimiter = "\\*|/|-|\\(|\\)|";
private final Pattern delim = Pattern.compile(delimiter);
private Matcher delim_matcher;
private String region;
private int regionStart;
private int regionEnd;
private int start;
private int end;
// Called by constructor, I stripped the constructor because trivial
private void Init(){
scanner = new Scanner(System.in);
region = scanner.next();
delim_matcher = delim.matcher(region);
regionStart = 0;
regionEnd = region.length();
}
private boolean nextDelimiter(){
boolean found = delim_matcher.find();
start = found ? delim_matcher.start() : delim_matcher.regionEnd();
end = found? delim_matcher.end(): delim_matcher.regionEnd();
return found;
}
private boolean hasPrefix(){
return start > regionStart;
}
public TokenType next() throws NoSuchElementException{
//find next delimiter ( symbol )
boolean found = nextDelimiter(); //TODO: see breakpoints here
if(hasPrefix()){
//there was something before the delimiter (keyword, identificator etc.)
decodePrefix( region.substring(regionStart,start) );
if(found)
delim_matcher.region(start,regionEnd); //reset to match symbol next time
regionStart = start; //hasPrefix -> false
return tokenType;
}
else if(!hasPrefix() && found){
decodeSymbol( region.substring(start,end));
delim_matcher.region(end,regionEnd); //reset to skip already found symbol
regionStart = end;
return tokenType;
}
else{
if(scanner.hasNext()){ //next is not a whitespace (because scanner already skip blanks)
region = scanner.next();
delim_matcher = delim.matcher(region);
regionStart = 0;
regionEnd = region.length();
return next();
}else
return tokenType = EOF;
}
}
public boolean hasNext() {
return tokenType != EOF; //EOF is a value of the enum "TokenType"
}
正如预期的那样,这个Tokenizer比Scanner类更有用。 Scanner类具有丢弃分隔符的缺点(因为在解析程序时符号可能是分隔符,我不希望它们被丢弃)。
此Tokenizer使用扫描程序检索空白分隔字符串,然后使用其他处理将字符串分割为符号。