除非注释位于带引号的字符串中,否则如何匹配注释?

Con*_*sed 4 java regex parsing regex-negation

所以我有一些字符串:

//Blah blah blach
// sdfkjlasdf
"Another //thing"
Run Code Online (Sandbox Code Playgroud)

我使用 java regex 来替换所有具有双斜杠的行,如下所示:

theString = Pattern.compile("//(.*?)\\n", Pattern.DOTALL).matcher(theString).replaceAll("");
Run Code Online (Sandbox Code Playgroud)

它在大多数情况下都有效,但问题是它删除了所有出现的情况,我需要找到一种方法让它不删除引用的出现。我该怎么做呢?

Bar*_*ers 5

您可以使用像 ANTLR 这样的第三方工具,而不是使用解析整个 Java 源文件的解析器,或者自己编写只解析您感兴趣的部分的东西。

ANTLR 能够仅定义您感兴趣的标记(当然还有可能会弄乱您的标记流的标记,例如多行注释以及字符串和字符文字)。因此,您只需要定义一个词法分析器(标记器的另一种说法)来正确处理这些标记。

这称为语法。在 ANTLR 中,这样的语法可能如下所示:

lexer grammar FuzzyJavaLexer;

options{filter=true;}

SingleLineComment
  :  '//' ~( '\r' | '\n' )*
  ;

MultiLineComment
  :  '/*' .* '*/'
  ;

StringLiteral
  :  '"' ( '\\' . | ~( '"' | '\\' ) )* '"'
  ;

CharLiteral
  :  '\'' ( '\\' . | ~( '\'' | '\\' ) )* '\''
  ;
Run Code Online (Sandbox Code Playgroud)

将以上内容保存在名为FuzzyJavaLexer.g. 现在在此处下载 ANTLR 3.2并将其保存在与您的文件相同的文件夹中FuzzyJavaLexer.g

执行以下命令:

java -cp antlr-3.2.jar org.antlr.Tool FuzzyJavaLexer.g
Run Code Online (Sandbox Code Playgroud)

这将创建一个FuzzyJavaLexer.java源类。

当然,您需要测试词法分析器,可以通过创建一个名为 的文件FuzzyJavaLexerTest.java并将以下代码复制到其中来完成:

import org.antlr.runtime.*;

public class FuzzyJavaLexerTest {
    public static void main(String[] args) throws Exception {
        String source = 
            "class Test {                                 \n"+
            "  String s = \" ... \\\" // no comment \";   \n"+
            "  /*                                         \n"+
            "   * also no comment: // foo                 \n"+
            "   */                                        \n"+
            "  char quote = '\"';                         \n"+
            "  // yes, a comment, finally!!!              \n"+
            "  int i = 0; // another comment              \n"+
            "}                                            \n";
        System.out.println("===== source =====");
        System.out.println(source);
        System.out.println("==================");
        ANTLRStringStream in = new ANTLRStringStream(source);
        FuzzyJavaLexer lexer = new FuzzyJavaLexer(in);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        for(Object obj : tokens.getTokens()) {
            Token token = (Token)obj;
            if(token.getType() == FuzzyJavaLexer.SingleLineComment) {
                System.out.println("Found a SingleLineComment on line "+token.getLine()+
                        ", starting at column "+token.getCharPositionInLine()+
                        ", text: "+token.getText());
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

接下来,通过执行以下操作来编译您的FuzzyJavaLexer.javaFuzzyJavaLexerTest.java

javac -cp .:antlr-3.2.jar *.java
Run Code Online (Sandbox Code Playgroud)

最后执行FuzzyJavaLexerTest.class文件:

// *nix/MacOS
java -cp .:antlr-3.2.jar FuzzyJavaLexerTest
Run Code Online (Sandbox Code Playgroud)

或者:

// Windows
java -cp .;antlr-3.2.jar FuzzyJavaLexerTest
Run Code Online (Sandbox Code Playgroud)

之后您将看到以下内容打印到控制台:

===== source =====
class Test {                                 
  String s = " ... \" // no comment ";   
  /*                                         
   * also no comment: // foo                 
   */                                        
  char quote = '"';                         
  // yes, a comment, finally!!!              
  int i = 0; // another comment              
}                                            

==================
Found a SingleLineComment on line 7, starting at column 2, text: // yes, a comment, finally!!!              
Found a SingleLineComment on line 8, starting at column 13, text: // another comment  
Run Code Online (Sandbox Code Playgroud)

很容易,嗯?:)