尝试通过Antlr 4 lexer / parser获取给定PHP文件的所有空行(仅行号)。我正在使用的语法可以在GitHub Antlr grammar for PHP上找到。
Whitespace标记定义为:
Whitespace: [ \t\r\n]+ -> skip;
我将其更改为:
Whitespace: (
' '
| '\t'
| '\r' '\n' { newline(); }
| '\n' { newline(); }
);
但它收集了几乎所有的行,因为每一行都以“ \ n ”结尾。任何专家建议都可以帮助我。
要测试的示例PHP:
<?php
//02-5002201-00001 5002201 - Machine hours test
function test()
{
/* Name: Test.php
Title: Demo
by: XYZ
*/
if (true && false)
{
echo "aa";
}
//TODO
echo <<<SEGDTA
<link rel="stylesheet" type="text/css" href="ui.css"/>
<script type="text/javascript" src="min.js"></script>
SEGDTA;
}
?>
答案 0 :(得分:2)
尝试这样的事情:
lexer grammar DemoLexer;
EmptyLine
: {super.getCharPositionInLine() == 0}? [ \t]* '\r'? '\n'
;
Whitespace
: [ \t\r\n] -> skip
;
Other
: .
;
如果我运行以下测试类:
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.Token;
public class Main {
public static void main(String[] args) {
String source = "foo\n" +
"\n" +
"bar\n" +
" \n" +
" baz \r\n" +
" \t\t\n" +
"\tend\n\n";
DemoLexer lexer = new DemoLexer(CharStreams.fromString(source));
for (Token t : lexer.getAllTokens()) {
String name = lexer.getTokenNames()[t.getType()];
String text = t.getText().replace("\r","\\r").replace("\n","\\n").replace("\t","\\t");
System.out.printf("%-20s '%s'\n", name, text);
}
}
}
这将打印出来:
Other 'f'
Other 'o'
Other 'o'
EmptyLine '\n'
Other 'b'
Other 'a'
Other 'r'
EmptyLine ' \n'
Other 'b'
Other 'a'
Other 'z'
EmptyLine ' \t\t\n'
Other 'e'
Other 'n'
Other 'd'
EmptyLine '\n'
请参阅:http://www.antlr.org/api/Java/org/antlr/v4/runtime/TokenSource.html#getCharPositionInLine()
答案 1 :(得分:1)
这是您使用PHP代码进行的唯一处理吗?如果是这样,您可以直接加载文件并计算空条目。在这种情况下不需要解析器。
<强>更新强>
因为你有这个解析器,你可以使用令牌流并遍历所有令牌。每当您看到换行符检查上一个令牌时,如果这也是换行符(或者这是流中的第一个令牌),您会找到一个空行。您甚至可以隐藏您的空白,因为令牌流将为您提供所有通道上的所有令牌(除非您对其进行过滤)。
无论如何,计算空行是一个语义步骤,解析器(正在执行语法步骤)不适合这个。
更新2
这里的代码应该有效(基于你的尝试):
CommonTokenStream tokenStream = new CommonTokenStream(new AntlrPHPLexer(charStream));
tokenStream.fill(); // Load all tokens.
int counter = 0;
List<Token> tokens = tokenStream.getTokens();
for (int i = 0; i < tokens.size(); ++i) {
if (tokens.get(i).getType() == AntlrPHPLexer.Linebreak) {
if (i == 0 || (tokens.get(i - 1).getType() == AntlrPHPLexer.Linebreak))
++counter;
}
}
您必须将空白分成两个规则:
Whitespace: ([ \t]+ | Linebreak) -> skip;
Linebreak: [\r\n];
请注意,我没有在Linebreak
Whitespace
中使用循环。{/ p>