【问题标题】:Split string using custom regex java使用自定义正则表达式 java 拆分字符串
【发布时间】:2017-05-07 00:28:20
【问题描述】:

我正在构建一个编译器。其中一些规格如下:

  • 字符串文字用美元符号 ("$") 括起来 - 例如。 $ 字符串示例 $
  • 注释用“*”括起来 - 例如。 * 示例评论 *
  • 注释可以存在于任何地方,除了操作之间 - 例如。 4 + * 示例评论 * 5 -(这是不允许的)

现在我必须拆分源代码行来对其进行标记。 示例案例:

PRINT $ THE FLOAT IS $ * DISPLAY THE RESULT *

我将对其进行标记,它应该产生:

PRINT - token is KEYWORD
THE FLOAT IS - token is STRING_LITERAL
DISPLAY THE RESULT - token is COMMENT 

我想知道获得此信息的最有效方法。请注意,我仍然必须验证字符串文字和注释的出现。 (例如,检查是否正确封闭)。到目前为止,我的方法是用空格分隔每一行,并且当词位包含“$”或“*”时,我将验证字符串文字。这是我的实现:

private void getLexemes(){
    for(String line : newSourceCode){
        String[] lexemesInALine = line.trim().split("[\\s]+");
        for(String lexemeInALine : lexemesInALine){
            if(!(lexemeInALine.contains("$"))){
                lexemes.add(lexemeInALine);
                tempTokens.add(findToken(lexemeInALine));
                line = line.replaceFirst(lexemeInALine,"").trim();
            }else{
                validateStringType(line);
                break;
            }
        }

感谢您的帮助。

【问题讨论】:

  • 您对手动词法分析感兴趣吗?您可以使用许多词法分析器/解析器生成器来专注于更高级别的部分。
  • 是的。你说对了。我对手工进行词法分析很感兴趣。
  • 但是我们不允许使用二级库。
  • 我认为我们可以使用标准库分词器。让我检查一下。谢谢。

标签: java regex string split compiler-construction


【解决方案1】:

我假设您的语言是确定性的和上下文无关的? 这意味着,您无法使用正则表达式正确解析它。

您需要的是一个处理令牌流的状态机。 Java 带有两个可能适合您的类:StreamTokenizerStringTokenizer

但您真正想要的是使用几十个解析器生成器之一。也许像ANTLR这样的东西。 这里有很多描述:

https://en.wikipedia.org/wiki/Comparison_of_parser_generators

如果这一切都失败了,它就是一个有限状态机。 类似的东西

public class Parsy {
    enum State { string, comment, token }
    void parse(StringTokenizer tokenizer) {
        State state = State.token;

        List<String> tokens = new ArrayList<>();
        while (tokenizer.hasMoreTokens()) {
            String token = tokenizer.nextToken();
            // figure out type of token
            if (token.length() == 1) {
                char delim = token.charAt(0);
                switch (delim) {
                    case '$':
                        switch (state) {
                            case token: {
                                // a string literal has started, emit what we have, start a string
                                printOut(tokens, state);
                                tokens.clear();
                                tokens.add(token);
                                state = State.string;
                                break;
                            }
                            case string: { // parsing a string, so this ends it
                                printOut(tokens, state);
                                tokens.clear();
                                state = State.token;
                                break;
                            }
                            case comment: { // $ is ignored since we are in a comment
                                tokens.add(token);
                                break;
                            }
                        }
                        break;
                    // ...
                }
            } else {
                // not a delimiter token
                tokens.add(token);
            }

        } // end of while
    if (state != State.token) {
       System.out.println("Oops! Syntax error. I'm still parsing" + state);
     }
    }
}

【讨论】:

  • 这不是确定性的(我认为),但是是的,它是上下文无关的,因此我不能使用 RE。我仍然需要阅读“StreamTokenizer”和“StringTokenizer”。谢谢你的链接
  • 顺便说一句,我们不允许在这个项目中使用二级库,因此我不能使用其他解析器生成器。
  • 编辑以概述如何在解析时跟踪状态。 enum State 跟踪您的解析器所在的位置:解析注释或字符串或任何其他标记
  • 我认为,唯一的限制是我不能在解析时包含验证,因为它直接“标记”字符串。不确定我是否正确。
  • 如果state != State.token 这意味着您仍在尝试解析评论或字符串。所以在while 结束后,检查state 的值。解析只有在state == State.token 时才会成功。请注意,我忽略了其他情况(即您需要添加 case '*': 遵循 '$' 示例)
猜你喜欢
  • 2011-07-18
  • 1970-01-01
  • 1970-01-01
  • 2011-10-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多