ANTLR4:令牌重写器——围绕删除压缩 space
ANTLR4: Token rewritter -- compacting space around a delete
我有以下示例语法:
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
我如何要求重写器删除之前的新行,直到找到另一个构造或文件的开头?
更新
我解决这个问题的第一个尝试是更改语法。事实是语法倾向于忽略回车 return 字符和 space 字符。
我用你的语法:
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)和一些需要class:
@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
我有以下示例语法:
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
我如何要求重写器删除之前的新行,直到找到另一个构造或文件的开头?
更新 我解决这个问题的第一个尝试是更改语法。事实是语法倾向于忽略回车 return 字符和 space 字符。
我用你的语法:
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)和一些需要class:
@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