regex 使用正则表达式查找Java注解(多行和单行)

olhwl3o2  于 12个月前  发布在  Java
关注(0)|答案(3)|浏览(118)

我在http://regexlib.com/上找到了下面的正则表达式

(\/\*(\s*|.*?)*\*\/)|(\/\/.*)

它在以下比赛中表现良好:

// Compute the exam average score for the midterm exam

/**
* The HelloWorld program implements an application that
*/

但它也倾向于匹配

http://regexr.com/foo.html?q=bar

至少从//开始
我是regex的新手,完全是个婴儿,但是我读到如果你在开头放一个插入符号,它会强制匹配从行的开头开始,但是这似乎在RegExr上不起作用。
我正在使用以下内容:

^(\/\*(\s*|.*?)*\*\/)|(\/\/.*)$
7rtdyuoh

7rtdyuoh1#

您要查找的正则表达式允许注解开头(///*)出现在任何地方,但不出现在每个正则表达式中,这些正则表达式会导致在内部包含这些子字符串的令牌。如果你看一下lexical structure of java language,你会发现唯一一个可以包含///*的词法元素是字符串文字,所以要匹配字符串中的注解,你必须匹配所有的字符串(因为在匹配之前没有字符串文字**,而匹配恰好开始一个字符串文字-并包含你的注解)
因此,注解前的字符串 * 应该由任何不以字符串字面量(没有结尾)为开始的有效字符串组成,因此,它可以被任意数量的字符串字面量四舍五入,其中任何字符串都不构成字符串字面量。如果你考虑一个字符串字面量,它应该与以下内容匹配:

\"()*\"

括号的内部必须填充不能是\n、单个"、单个\,也不能是导致有效"的unicode文字\uxxxx(Java禁止使用将被编码为Unicode序列的普通Java字符,所以最后一种情况不适用),但可以是转义的\\或转义的\",因此这将导致

\"([^\\\"\n]|\\.)*\"

这可以重复任意次数,并在任何不是"的字符之前(应该开始考虑的最后一部分):

([^\\"](\"([^\\\"\n]|\\.)*\")?)*

那么,我们的有效字符串的前一部分应该被这个字符串匹配,然后是注解字符串,它可以是两种形式中的任何一种:

\/\/[^\n]*$

/\*([^\*]|\*[^\/])*\*\/

(this is,一个斜杠,一个星号(转义),以及任何数量的东西,可以是:不同于**的序列后接非/的序列,最终得到*/序列)
这些可以被归为一个备选组,如:

(\/\/[^\n]*\n|\/\*([^\*]|\*[^\/])*\*\/)

最后,我们的表达式显示:

^([^\\"](\"([^\\\"\n]|\\.)*\")?)*(\/\/[^\n]*|\/\*([^\*]|\*[^/])*\*\/)

但是你应该注意,你匹配的注解不是从开头开始,而是从第四组开始(在第四个左括号的标记中),并且正则表达式应该从开头就匹配字符串,参见demo

注意事项

我认为你不仅匹配了评论,还匹配了之前的文字。这使得结果匹配由您想要的匹配之前的内容和匹配的内容组成。另外,如果你尝试这个正则表达式,并按顺序添加了几个注解,它只会匹配最后一个,因为我们还没有讨论/* ... /* .... */序列的情况(注解也可以嵌入到注解中,但考虑到这种情况,你会永远讨厌正则表达式。科普这个问题的正确方法是编写一个lex/flex规范来获取java令牌,并且只获取它们,但这超出了本说明的范围。看一个可能有效的例子here

rbl8hiat

rbl8hiat2#

REGEXP FOR SINGLE & MULTI-LINE COMMENTS(JS / C / C# / JAVA /etc.)

在VS Codium和https://regex101.com上测试

\/\*[\s\S\n]*?\*\/|\/\/.*$

这将正确匹配:

// single line comments

  /**
   * multi
   * line
   * comments
   * // including nested inline comments 
   * and without tripping on URL slashes (https://www.example.com)
   */

  /* single line comments written using multi-line delimiters */

  // /* single line comments written using MLDs and within a regular single line comment */

在regexp前面加上两个额外的*(一个在开头,一个在|),它还将选择单行和多行注解之前的所有水平空白:

*\/\*[\s\S\n]*?\*\/| *\/\/.*$

will_select_this_area_as_well_together_with // the content of a deeply nested comment

当你必须对注解做一些外部工作时,这会很方便。翻译)。通过复制空格,当你将注解粘贴回代码中时,你可以确保它们会滑回它们的原始位置(按列)。
也就是说,为了避免错误并使这些额外的部分更加清晰,也可以使用[[:space:]]*重写它,如下所示:

[[:space:]]*\/\*[\s\S\n]*?\*\/|[[:space:]]*\/\/.*$

然而,不幸的是,VS Code/Codium似乎还不支持这种语法,所以我坚持使用*形式。
希望能帮上忙!

注意:如果你在https://regex101.com/上测试,请确保使用位于表达式末尾“硬编码”/之后的开关设置gm标志。

8yoxcaq7

8yoxcaq73#

你可以试试这个模式:

(?ms)^[^'"\n]*?(?:(?:"(?:\\.|[^"])*"|'\\?.')[^'"\n]*?)*((?:(?://[^\n]*|/\*.*?\*/)[ \t]*)+)

这将捕获组1中的注解,但仅当注解不在字符串中时。Demo.
细分:

(?ms)                 multiline flag, makes ^ match at the start of a line
                      singleline flag makes . match newlines
^                     start of line
[^'"\n]*?             match anything but " or ' or newline
(?:                   then, any number strings:
    (?:
        "             start with a quote...
        (?:           ...followed by any number of...
            \\.       ...a backslash and the escaped character
        |             or
            [^"]      any character other than "
        )*
        "             ...and finally the closing quote
    |                 or...
        '\\?.'        a single character in single quotes, possibly escaped
    )
    [^'"\n]*?         and everything up to the next string or newline
)*
(                     finally, capture (any number of) comments:
    (?:
        (?:           either...
            //[^\n]*  a single line comment
        |             or
            /\*.*?\*/ a multiline comment
        )
        [ \t]*        and any subsequent comments if only separated by whitespace
    )+
)

相关问题