【问题标题】:How to find (* comments *) using Java's regexp?如何使用 Java 正则表达式查找 (* comments *)?
【发布时间】:2011-07-23 23:32:01
【问题描述】:

我不知道如何使用可以在评论中出现的 '(', ')' 和 '*'。评论是多行的。

【问题讨论】:

  • 如果 (* comment *) 是注释,那么正则表达式无法真正处理 (* zz (* zz *)(* zz *) zz *)
  • 我不清楚这个问题是否只是关于掩盖括号和星号,还是关于上下文识别(cmets 中的字符串、字符串中的 cmets、嵌套 cmets 等)。跨度>
  • @user unknown - 我知道如何避开括号和星号,这个问题是关于如何处理嵌套的,包含 * 和(或)cmets。

标签: java regex pascal


【解决方案1】:

一个简单的处理模式是:

\(\*(.*?)\*\)

示例:http://www.rubular.com/r/afqLCDssIx

您可能还想设置单行标志(?s)\(\*(.*?)\*\)

请注意,它不处理字符串中的(* 或其他奇怪组合之类的情况。最好的办法是使用解析器,例如 ANTLR,它已经准备好了 Pascal grammar (direct link)。

【讨论】:

  • +1 用于查找包含此内容的实际语法。只是为了完整性:即使使用解析器生成器,处理潜在嵌套的 cmets 也可能很棘手。此外,您需要了解其余(非评论)内容的语法。例如。如果我不知道其余的语法,那么仅仅寻找一个开头的(* 标记可能会导致我在字符串文字中找到一些东西。
  • @phooji - 谢谢!解析器甚至应该处理嵌套的结构——它对整个代码结构来说足够容易。也就是说,我怀疑(* zz *) zz *) 是否有效——实际上很少有语言允许嵌套 cmets。 /* 1 /* 2 */ 1 */ 不会传入任何 C++ 编译器 :)
  • 我想强调一下,你必须在 java 中屏蔽 \(\*(.*?)\*\) 的反斜杠,在 Javacode 中看起来像这样 String r = "\\(\\*(.*?)\\*\\)";
  • @Kobi:对。我想我正在考虑一个更老派的 Lex/Yacc 设置,为了解析 cmets,你将词法分析器置于特殊的“注释”模式。
  • 其实我参加了一个编程比赛,我在第一个任务上花了很多时间,但是还有一个:“Delete all {}, // and (* *) cmets from input帕斯卡码”。我只有 4 分钟的时间,所以我决定使用 Java 的正则表达式。我设法删除了 // 和 {} cmets,但我的第三个正则表达式效果不佳。因此,据我所知,该任务应该在不使用正则表达式的情况下完成。但是,使用您的正则表达式,我的程序也许可以通过大多数测试,但是,非常感谢您的帮助!
【解决方案2】:

如果要查找 /* */ 示例的最内层嵌套注释

/* 
/*
comment1
/*
comment2
*/
*/
*/

正则表达式将是

\/\*[^/*]*(?:(?!\/\*|\*\/)[/*][^/*]*)*\*\/

这会找到

/*
comment2
*/

【讨论】:

    【解决方案3】:

    关于嵌套 cmets 的处理,虽然确实不能使用 Java 正则表达式来匹配 outermost 注释,但您可以制作一个匹配 em>innermost 评论(有一些值得注意的例外 - 请参阅下面的警告)。 (请注意:\(\*(.*?)\*\) 表达式在这种情况下将不起作用,因为它不能正确匹配最里面的注释。)以下是一个经过测试的 java 程序,它使用一个(重注释的)正则表达式,它只匹配最里面的 cmets,并应用这个以迭代方式正确剥离嵌套的 cmets:

    public class TEST {
        public static void main(String[] args) {
            String subjectString = "out1 (* c1 *) out2 (* c2 (* c3 *) c2 *) out3";
            String regex = "" +
                "# Match an innermost pascal '(*...*)' style comment.\n" +
                "\\(\\*      # Comment opening literal delimiter.\n" +
                "[^(*]*      # {normal*} Zero or more non'(', non-'*'.\n" +
                "(?:         # Begin {(special normal*)*} construct.\n" +
                "  (?!       # If we are not at the start of either...\n" +
                "    \\(\\*  # a nested comment\n" +
                "  | \\*\\)  # or the end of this comment,\n" +
                "  ) [(*]    # then ok to match a '(' or '*'.\n" +
                "  [^(*]*    # more {normal*}.\n" +
                ")*          # end {(special normal*)*} construct.\n" +
                "\\*\\)      # Comment closing literal delimiter.";
            String resultString = null;
            java.util.regex.Pattern p = java.util.regex.Pattern.compile(
                        regex,
                        java.util.regex.Pattern.COMMENTS);
            java.util.regex.Matcher m = p.matcher(subjectString);
            while (m.find())
            { // Iterate until there are no more "(* comments *)".
                resultString = m.replaceAll("");
                m = p.matcher(resultString);
            }
            System.out.println(resultString);
        }
    }
    

    这里是正则表达式的简短版本(原生正则表达式格式):

    \(\*[^(*]*(?:(?!\(\*|\*\))[(*][^(*]*)*\*\)
    

    请注意,此正则表达式实现了 Jeffrey Friedl 的 “Unrolling-the-loop” 高效技术,并且速度非常快。 (参见:Mastering Regular Expressions (3rd Edition))。

    警告:如果任何注释分隔符(即(**))出现在字符串文字中,这肯定不会正常工作,因此不应用于一般解析。但是像这样的正则表达式可以不时使用 - 例如在编辑器中进行快速而肮脏的搜索。

    对于想要处理嵌套 C 风格 cmets 的人,另请参阅我对 a similar question 的回答。

    【讨论】:

      猜你喜欢
      • 2011-04-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-27
      相关资源
      最近更新 更多