antlr4 - ANTLR4:令牌重写器——压缩删除周围的空间
问题描述
我有以下示例语法:
start: (comments | removes)*
comments: COMMENT;
removes: REMOVE_ME;
COMMENT: ';'~('\n'|'\r')*;
REMOVE_ME: 'remove_me';
fragment NEW_LINE: (('\n')
|('\r')
|('\r\n'));
NEW_LINES: NEW_LINE+ -> channel(HIDDEN);
OTHER: . -> channel(HIDDEN);
我有以下示例文本
; comments here
; please come closer comment!
remove_me
remove_me
; comment
当我访问每个规则时,我可以使用令牌重写器来删除令牌
rewritter.delete(ctx.REMOVE_ME);
但是我想做的是,在 REMOVE_ME 之前清理空的新行,并最终得到如下文本。
; comments here
; please come closer comment!
; comment
我如何要求重写器删除以前的新行,直到找到另一个构造或文件的开头?
解决方案
更新 我第一次尝试解决这个问题是改变语法。事实是语法倾向于忽略回车符和空格字符。
我用你的语法:
grammar Toek;
start: (comments|removes)*;
comments: COMMENT;
removes: REMOVE_ME;
COMMENT: ';'~('\n'|'\r')*;
REMOVE_ME: 'remove_me';
fragment NEW_LINE: (('\n')
|('\r')
|('\r\n'));
NEW_LINES: NEW_LINE+ -> channel(HIDDEN);
OTHER: . -> channel(HIDDEN);
然后我写了一个简单的 JUNIT 测试来解析一个字符串(你写的那个)并应用我的解决方案。解决方案基于函数式编程(只是为了简化代码,没有必要)。当 ANTLR 完成替换您指定的规则时,我获取获得的字符串,将其拆分为行并将所有行删除为空。
测试(JUNIT)和一些需要的类:
@Test
public void testOK() throws Throwable {
final String text = "; comments here\n" +
"; please come closer comment!" +
"\n" +
"\n" +
"remove_me" +
"\n"+
"\n" +
"remove_me" +
"\n" +
"; comment";
ParseTreeWalker walker = new ParseTreeWalker();
List<Triple<Token, Token, String>> replace = new ArrayList<>();
ToekBaseListener listener = new ToekBaseListener() {
@Override
public void enterRemoves(RemovesContext ctx) {
System.out.println("-: [" + ctx.getText() + "]");
replace.add(new Pair<Token, Token,>(ctx.start, ctx.stop));
}
};
ToekLexer lexer = new ToekLexer(CharStreams.fromString(text));
CommonTokenStream tokens = new CommonTokenStream(lexer);
ToekParser parser = new ToekParser(tokens);
parser.removeErrorListeners();
parser.addErrorListener(new JQLBaseErrorListener() {
@Override
public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line,
int charPositionInLine, String msg, RecognitionException e) {
System.out.println(String.format("unespected char at pos %s of text '%s'", charPositionInLine, text));
}
});
ParserRuleContext context = parser.start();
walker.walk(listener, context);
TokenStreamRewriter rewriter = new TokenStreamRewriter(tokens);
for (Triple<Token, Token, String> item : replace) {
rewriter.replace(item.value0, item.value1, "");
}
String solution=split(rewriter.getText());
System.out.println(solution);
}
...
public class Pair {
public Pair(double k ,double v) {
key=k;
value=v;
}
private String key;
private String value;
public String getKey() { return key; }
public String getValue() { return value; }
}
以及负责解决的方法。一些解释:获取字符串,在流中转换(由'\n'分割),仅过滤大小> 0的元素,重新压缩在一起。
public static String removeBlankLines(String str) {
return Stream.of(str.split("\n"))
.filter(elem -> elem!=null && elem.trim().length()>0)
.collect(Collectors.joining("\n"));
}
输出就像你想要的:
; comments here
; please come closer comment!
; comment
推荐阅读
- code-coverage - OpenCover 是否并行运行测试?有没有不可以的选项?
- python - 无法使用 patool 包提取 gz 文件
- r - 如何计算R中不同类别之间的重叠
- python - 使用 Numpy 缓解浮点逼近问题
- swift - 如何在 Swift 中使用这个 fetchRequest()?
- sql - 为什么@@ROWCOUNT 为使用 sp_executesql 的 NULL 语句返回 1?
- android - 反正有没有使用矩形区域作为地理围栏?
- amazon-web-services - 如何使用 EC2 上的配置文件访问 S3?(sts.amazonaws.com:443 错误)
- python - 找出列表和集合之间的区别
- python - /cart/update-transaction/0cqydz1f/ 处的 IntegrityError