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

how to rearrange method access modifier using regex

我是正则表达式的新手。 我正在尝试使用正则表达式为声纳重新排列方法访问修饰符 Rule

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

输入示例
static public void main(String[] args)
然后使用
</code> <br> 替换,但我得到相同的结果。 </p> <p>输出应该按照正确的访问修饰符顺序,例如首先 public 然后是静态的:<br> <code>public static void main (String[] args)
方法签名应遵循以下顺序:
public or protected or private 然后如果适用
abstract or static 然后如果适用
final 然后如果适用
volatile 然后如果适用
synchronized 然后如果适用
native 然后如果适用
stictfp

RegexExampleLink

你所拥有的基本上就是你所需要的,你只需要将碎片拼凑起来。正则表达式应该是

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

捕获组索引 决定什么应该去哪里。如果您可以捕获整个方法签名,即。

static public void main(String[] args) 

作为一个字符串,那么上面的正则表达式将在捕获组 1 中捕获 public,在捕获组 2 中捕获 staticTry it out here!

使用 java.util.regex.{Pattern,Matcher} to get the capture groups, then rearrange them manually, making sure to use String.trim() 删除多余的空格。

这是一个可行的解决方案

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());

  }

}

示例输出:

17:34 |aww@airy test| javac Signature.java 

17:35 |aww@airy test| java Signature

Original method signature:
    synchronized static final native public void barFooer(int foo, double bar)

New method signature:
    public static final synchronized native void barFooer(int foo, double bar)

此代码也可从以下要点获得: https://gist.github.com/awwsmm/85575d2756f69b95564ff11b8ee105fd

问题是您的 (…)|(…)|(…)|… 形式的模式指定了备选方案,而只有一个必须匹配。因此,您的模式一次只匹配一个关键字,其中一组包含匹配的关键字,而所有其他组为空。然后,当您将该匹配项替换为 </code> 时,您将替换关键字本身,其他组没有任何效果。反复应用操作仍然没有效果。</p> <p>因此您需要一个匹配整个关键字序列的模式,填充存在关键字的组。为此,请使用 <code>+ 量词将您的正则表达式包含在另一组中,以匹配至少一个关键字,但尽可能多。重复组中的捕获组的好处是,如果他们在下一次重复中不匹配,他们会一直记住上一次匹配。因此,在识别重复组的匹配项后,如果序列中有一个关键字,则每个子组都捕获了一个关键字。

所以最终的模式可能看起来像

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

online demo

在这里,我确定了更多的互斥关键字,将数量减少到五组。我在组中包含了后续的 white-space(使用像 ((?:keyword1|keyword2)\s+) 这样的子模式,在非捕获组中列出备选方案)。这样,替换中就会有正确的间距。我在开头添加了一个单词边界(\b)以确保没有错误匹配(例如单词nonstatic)。由于强制性的 white-space.

,关键字后的单词边界已经隐含

在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+)"
    + ")+",
  ""
);

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

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