ОБНОВЛЕНИЕ Моей первой попыткой решить эту проблему было изменение грамматики. Дело в том, что грамматика имеет тенденцию игнорировать символы возврата каретки и пробелы.
Я использую вашу грамматику:
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