java - 如何使用 util.regex.Matcher (java) 创建 Tokenizer?

标签 java regex matcher

实际上我有以下正则表达式 token (学校职责):

Identificator = [a-zA-Z_][a-zA-Z0-9_]*
Integer = [0-9]+
ReservedKeywords = true|false|while|foreach|for|plus
Symbols = *|/|-|\(|\)|
Blank = \s+

我无法使用 Scanner 类,因为某些标记之间可能没有空格。请注意,解析器(假定它接收到正确的标记)已准备就绪,并且还可以对 AST 进行类型检查和评估。仅缺少“最简单”的部分,因此“Tokenizer”并且互联网上没有足够完整的示例。

我不明白 util.regex.Matcher 类的文档,它非常令人困惑。

实际上是合法的

  • [ 保留关键字|标识符|整数]后跟一个符号
  • 符号后跟[保留关键字|标识符|整数|符号]
  • [ 保留关键字|标识符|整数|符号 ] 后跟一个空格
  • 空格后跟 [ 保留关键字|标识符|整数|符号]
  • [ 保留关键字|标识符|整数|符号|空白],后跟流/字符串结尾

我们必须使用 Matcher 类,因此无论如何都没有机会对分词器进行硬编码(这太简单了:简单的状态机+映射查找,但我们不允许这样做)。

分词器必须有 2 个方法(“hasNext”和“next”)。

我需要一些示例来了解如何使用匹配器将字符串与取决于上下文的分隔符进行匹配(Scanner 类不适合,因为它会“吃掉”分隔符,而分隔符是语法的一部分,请参见以下示例:

(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)

这是不正确的。

我需要执行以下操作:

给定一组模式(标识符、整数、保留关键字、符号、空白等)。我需要匹配这些模式中第一次出现的情况。分隔符是“符号|空白” 但分隔符不应被丢弃,而是应作为标记返回。 这必须使用 Matcher 类来完成。

展示如何使用返回的分隔符“Blank | Symbols”或分隔字符串或分隔符本身来标记字符串就足够了。

最佳答案

在花了很多时间弄清楚匹配器的工作原理之后,我能够创建一个比通常的扫描器更复杂的标记器。由于没有人回答,这是相关部分(因为这是学校作业,我可以分享代码):

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 类的缺点是丢弃分隔符(因为在解析程序时符号可能是分隔符,我不希望它们被丢弃)。

此分词器使用扫描器检索空白分隔字符串,然后使用其他处理来分割符号周围的字符串。

关于java - 如何使用 util.regex.Matcher (java) 创建 Tokenizer?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24772860/

相关文章:

regex - Apache Spark : how to transform Data Frame column with regex to another Data Frame?

python - 如何选择网站中除给定类别之外的所有 URL?

java正则表达式模式未闭合字符类

java - Android:简单的 XML SAX 解析器 - 反复显示相同的数据

java - 抽象类中的非抽象空方法是什么意思

java - 单击按钮后管理 mysql 连接

python - 正则表达式在条件 Python 之前查找特定字母

java - index 和 offset 在 Java Regex 中有不同的含义?

java - 如何通过正则表达式检测奇数长度的01序列

java - JDBC MYSQL 语法错误异常