我是否用此令牌替换代码重新发明了轮子?

时间:2018-08-25 08:53:31

标签: java regex java.util.scanner tokenize

在一个用例中,我有一行包含嵌套标记的文本(例如{}),并且我希望转换嵌套在特定深度的某些子字符串。

例如,在深度1处将moo一词大写。

  

moo [moo [moo moo]] moo->

     

moo [MOO [moo moo]] moo

达成者:

replaceTokens(input, 1, "[", "]", "moo", String::toUpperCase);

或者在实际示例中,提供尚未使用青色颜色序列着色的“ --options”:

  

@ | blue --ignoreLog | @起作用,但是--ignoreOutput使所有内容静音。 ->

     

@ | blue --ignoreLog | @可以,但是@ | cyan --ignoreOutput | @可以使所有内容静音。

达成者:

replaceTokens(input, 0, "@|", "|@", "--\\w*", s -> format("@|cyan %s|@", s));

我已经实现了这种逻辑,尽管我对此感觉很好(也许除了性能),但我也觉得自己是在重新发明轮子。这是我的实现方式:

set currentPos to zero

while (input line not fully consumed) {
    take the remaining line

    if the open token is matched, add to output, increase counter and advance pos accordingly
    else if the close token is matched, add to output, decrease counter and advance pos accordingly
    else if the counter matches provided depth and given regex matches, invoke replacer function and advance pos accordingly
    else just record the next character and advance pos by 1
}

这是实际的实现方式:

public static String replaceNestedTokens(String lineWithTokens, int nestingDepth, String tokenOpen, String tokenClose, String tokenRegexToReplace, Function<String, String> tokenReplacer) {
    final Pattern startsWithOpen = compile(quote(tokenOpen));
    final Pattern startsWithClose = compile(quote(tokenClose));
    final Pattern startsWithTokenToReplace = compile(format("(?<token>%s)", tokenRegexToReplace));

    final StringBuilder lineWithTokensReplaced = new StringBuilder();

    int countOpenTokens = 0;
    int pos = 0;

    while (pos < lineWithTokens.length()) {
        final String remainingLine = lineWithTokens.substring(pos);

        if (startsWithOpen.matcher(remainingLine).lookingAt()) {
            countOpenTokens++;
            lineWithTokensReplaced.append(tokenOpen);
            pos += tokenOpen.length();
        } else if (startsWithClose.matcher(remainingLine).lookingAt()) {
            countOpenTokens--;
            lineWithTokensReplaced.append(tokenClose);
            pos += tokenClose.length();
        } else if (countOpenTokens == nestingDepth) {
            Matcher startsWithTokenMatcher = startsWithTokenToReplace.matcher(remainingLine);
            if (startsWithTokenMatcher.lookingAt()) {
                String matchedToken = startsWithTokenMatcher.group("token");
                lineWithTokensReplaced.append(tokenReplacer.apply(matchedToken));
                pos += matchedToken.length();
            } else {
                lineWithTokensReplaced.append(lineWithTokens.charAt(pos++));
            }
        } else {
            lineWithTokensReplaced.append(lineWithTokens.charAt(pos++));
        }
        assumeTrue(countOpenTokens >= 0, "Unbalanced token sets: closed token without open token\n\t" + lineWithTokens);
    }
    assumeTrue(countOpenTokens == 0, "Unbalanced token sets: open token without closed token\n\t" + lineWithTokens);
    return lineWithTokensReplaced.toString();
}

我无法使其与thisthis(或Scanner)解决方案等正则表达式一起使用,但我觉得我正在重新发明轮子,可以使用(普通Java)解决此问题较少代码的现成类。另外,我非常确定这是所有内联模式/匹配器实例和子字符串的性能噩梦。

建议?

1 个答案:

答案 0 :(得分:0)

您可能正在使用ANTLR之类的解析器来创建语法来描述您的语言或语法。然后,使用侦听器或访问者对令牌进行解释。

语法示例如下(我可以从您的代码中推断出):

grammar Expr;       
prog:   (expr NEWLINE)* ;
expr:   id '[' expr ']'
    |   '@|' expr '|@'
    |   '--ignoreLog' expr
    |   '--ignoreOutput' expr
    |   string
    ;
string: [a-zA-Z0-9];
NEWLINE : [\r\n]+ ;