如何使用正则表达式重新排列方法访问修饰符

时间:2018-08-18 11:08:48

标签: java regex sonarqube-scan regex-group

我是regex的新手。 我试图使用正则表达式为声纳Rule

重新排列方法访问修饰符
(public|protected|private)|(abstract|static)|(final)|(volatile)|(synchronized)|(native)|(strictfp)

将输入示例作为
static public void main(String[] args)
,然后使用
$1$2$3$4$5$6$7
进行替换,但我得到的结果相同。

输出应该按照正确的访问修饰符顺序排列,例如第一个public,然后是static:
public static void main (String[] args)
方法签名应遵循顺序:
public or protected or private,然后(如果适用)
abstract or static,然后(如果适用)
final,然后(如果适用)
volatile,然后(如果适用)
synchronized,然后(如果适用)
native,然后(如果适用)
stictfp

RegexExampleLink

2 个答案:

答案 0 :(得分:3)

问题是您的(…)|(…)|(…)|…格式的模式指定了替代项,而只有一个必须匹配。因此,您的模式一次只匹配一个关键字,一组包含匹配关键字,而所有其他组均为空。然后,当您将匹配项替换为$1$2$3$4$5$6$7时,您将关键字替换为自身,其他组则没有任何效果。重复应用该操作仍然无效。

因此,您需要一种与关键字的整个序列匹配的模式,以填充存在关键字的组。为此,请使用+量词将正则表达式包含在另一组中,以匹配至少一个关键字,但要与存在的关键字一样多。重复组中的捕获组的好处是,如果它们在下一个重复中不匹配,则他们会记住自己的前一场比赛。因此,在确定重复组的匹配项之后,如果序列中有一个,则每个子组都捕获了一个关键字。

因此生成的模式看起来像

(?:\b((?:public|protected|private)\s+)|((?:abstract|static)\s+)|(final\s+)|((?:volatile|synchronized)\s+)|((?:native|strictfp)\s+))+

online demo

在这里,我确定了更多的互斥关键字,将数量减少到了五个组。我在组中包括了后续的空格(使用类似((?:keyword1|keyword2)\s+)的子模式,在非捕获组中列出了替代项)。这样,替换中将有正确的间距。我在开头(\b)处添加了一个单词边界,以确保没有错误的匹配(例如单词nonstatic)。由于必须使用空格,因此已经暗示了关键字后的单词边界。

在Java代码中:

String in = "synchronized public final static native void main(String[] args)";
String out = in.replaceAll(
      "(?:\\b"
    +   "((?:public|protected|private)\\s+)|((?:abstract|static)\\s+)|"
    +   "(final\\s+)|((?:volatile|synchronized)\\s+)|((?:native|strictfp)\\s+)"
    + ")+",
  "$1$2$3$4$5"
);

System.out.println(out);// public static final synchronized native void main(String[] args)

但是请注意,这有局限性。对于Java语言,注释是修饰符,因此可以与关键字修饰符自由混合,例如, static @Deprecated public。由于注释具有递归语法(注释可能包含注释,但是即使是更简单的情况(例如嵌套常量表达式或数组初始化程序)也可能具有不同的深度),因此无法通过单个正则表达式解析所有有效注释值。因此,以上解决方案仅处理关键字,并且无论您可能添加多少注释案例,您都必须在某处进行切入,考虑其他所有不支持的内容。

答案 1 :(得分:-1)

您所拥有的基本上就是您所需要的,您只需要将各个部分放在一起。正则表达式应为

 app:cardPreventCornerOverlap="true"
 app:cardUseCompatPadding="false"
 app:contentPadding="0dp"
 app:contentPaddingBottom="0dp"

捕获组索引是确定应该去哪里的内容。如果您可以捕获整个方法签名,即。

(public|protected|private)|(abstract|static)|(final)|(volatile)|(synchronized)|(native)|(strictfp)

作为字符串,则上面的正则表达式将在捕获组1中捕获static public void main(String[] args) ,在捕获组2中捕获publicTry it out here!

使用java.util.regex。{PatternMatcher}获取捕获组,然后手动重新排列捕获组,确保使用String.trim()删除多余的空格。

这是一个可行的解决方案

static

示例输出:

import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class Signature {

  public static void main(String[] args) {

    // slightly more complex example to show off capabilities of method
    String oldSignature = "synchronized static final native public void barFooer(int foo, double bar)";

    // echo to user
    System.out.printf("%nOriginal method signature:%n    %s%n%n", oldSignature);

    // group number (          1             ) (        2      ) (  3  ) (   4    ) (     5      ) (   6  ) (   7    )
    String regex = "(public|protected|private)|(abstract|static)|(final)|(volatile)|(synchronized)|(native)|(strictfp)";

    // create regex.Pattern and regex.Matcher objects
    Pattern pat = Pattern.compile(regex);
    Matcher mat = pat.matcher(oldSignature);

    // array to hold signature "groups" in correct order
    String[] groups = new String[7];

    // int to hold end of last matched group
    int endOfLastGroup = -1;

    while (mat.find()) {
      for (int gg = 1; gg <= 7; ++gg) {

        // get the new matched group and any previous match in this group
        String newGroup = mat.group(gg);
        String oldGroup = groups[gg-1];

        // where does the new matched group end?
        int endOfNewGroup = mat.end();

        // did we find a new match in this group?
        if (newGroup != null) {

          // cannot have, for instance, both "public" and "private"
          if (oldGroup != null) {
            System.err.printf("Error! Signature cannot contain both '%s' and '%s'!%n", newGroup.trim(), oldGroup.trim());
            return;
          }

          // otherwise, new group found!
          groups[gg-1] = newGroup;

          // find furthest-right matched group end
          if (mat.end() > endOfLastGroup)
            endOfLastGroup = mat.end();
    } } }

    // new signature will be constructed with a StringBuilder
    StringBuilder newSignature = new StringBuilder("");

    // add groups to new signature in correct order
    for (String group : groups) {
      if (group != null) {
        newSignature.append(group.trim());
        newSignature.append(" ");
    } }

    // finally, add the return type, method name, arguments, etc.
    newSignature.append(oldSignature.substring(endOfLastGroup).trim());

    // echo to user
    System.out.printf("New method signature:%n    %s%n%n", newSignature.toString());

  }

}

以下要点也提供此代码: https://gist.github.com/awwsmm/85575d2756f69b95564ff11b8ee105fd