wake-up-neo.net

Kann ich Gruppen in Java-Regex ersetzen?

Ich habe diesen Code, und ich möchte wissen, ob ich in Java-Regex nur Gruppen (nicht alle Muster) ersetzen kann.

 //...
 Pattern p = Pattern.compile("(\\d).*(\\d)");
    String input = "6 example input 4";
    Matcher m = p.matcher(input);
    if (m.find()) {

        //Now I want replace group one ( (\\d) ) with number 
       //and group two (too (\\d) ) with 1, but I don't know how.

    }
77
wokena

Verwenden Sie $n (wobei n eine Ziffer ist), um auf erfasste Untersequenzen in replaceFirst(...) zu verweisen. Ich gehe davon aus, dass Sie die erste Gruppe durch die Literalzeichenfolge "number" und die zweite Gruppe durch den Wert der ersten Gruppe ersetzen wollten.

Pattern p = Pattern.compile("(\\d)(.*)(\\d)");
String input = "6 example input 4";
Matcher m = p.matcher(input);
if (m.find()) {
    // replace first number with "number" and second number with the first
    String output = m.replaceFirst("number $3$1");  // number 46
}

Betrachten Sie (\D+) für die zweite Gruppe anstelle von (.*). * ist ein gieriger Matcher und verbraucht zuerst die letzte Ziffer. Der Matcher muss dann zurückgehen, wenn er feststellt, dass der endgültige (\d) keine Übereinstimmungen aufweist, bevor er mit der letzten Ziffer übereinstimmt.

102
Chadwick

Sie können Matcher#start(group) und Matcher#end(group) verwenden, um eine generische Ersetzungsmethode zu erstellen:

public static String replaceGroup(String regex, String source, int groupToReplace, String replacement) {
    return replaceGroup(regex, source, groupToReplace, 1, replacement);
}

public static String replaceGroup(String regex, String source, int groupToReplace, int groupOccurrence, String replacement) {
    Matcher m = Pattern.compile(regex).matcher(source);
    for (int i = 0; i < groupOccurrence; i++)
        if (!m.find()) return source; // pattern not met, may also throw an exception here
    return new StringBuilder(source).replace(m.start(groupToReplace), m.end(groupToReplace), replacement).toString();
}

public static void main(String[] args) {
    // replace with "%" what was matched by group 1 
    // input: aaa123ccc
    // output: %123ccc
    System.out.println(replaceGroup("([a-z]+)([0-9]+)([a-z]+)", "aaa123ccc", 1, "%"));

    // replace with "!!!" what was matched the 4th time by the group 2
    // input: a1b2c3d4e5
    // output: a1b2c3d!!!e5
    System.out.println(replaceGroup("([a-z])(\\d)", "a1b2c3d4e5", 2, 4, "!!!"));
}

Überprüfen Sie Online-Demo hier.

44
acdcjunior

Fügen Sie eine dritte Gruppe hinzu, indem Sie Parasiten um .* hinzufügen und dann die Untersequenz durch "number" + m.group(2) + "1" ersetzen. z.B.:

String output = m.replaceFirst("number" + m.group(2) + "1");
9
mkb

Tut mir leid, ein totes Pferd zu schlagen, aber es ist irgendwie komisch, dass niemand darauf hingewiesen hat - "Ja, das ist möglich, aber dies ist das Gegenteil von der Verwendung von Gruppen, die im wirklichen Leben erfasst werden".

Wenn Sie Regex so verwenden, wie es verwendet werden soll, ist die Lösung so einfach wie folgt:

"6 example input 4".replaceAll("(?:\\d)(.*)(?:\\d)", "number$11");

Oder, wie Shmosel unten zu Recht darauf hinweist,

"6 example input 4".replaceAll("\d(.*)\d", "number$11");

... da es in Ihrem Regex keinen guten Grund gibt, die Dezimalzahlen überhaupt zu gruppieren. 

Normalerweise verwenden Sie Capturing-Gruppen nicht für die Teile der Zeichenfolge, die Sie verwerfen möchten, sondern Sie verwenden sie für den Teil der Zeichenfolge, den Sie möchten. Keep .

Wenn Sie wirklich Gruppen wünschen, die Sie ersetzen möchten, möchten Sie stattdessen eine Templating Engine (z. B. Schnurrbart, EJS, StringTemplate, ...).


Abgesehen von den Neugierigen sind auch Gruppen, die keine Gruppen erfassen, nur für den Fall, dass die Regex-Engine sie benötigt, um variablen Text zu erkennen und zu überspringen. Zum Beispiel in

(?:abc)*(capture me)(?:bcd)*

sie brauchen sie, wenn Ihre Eingabe entweder wie "abcabc capture me bcdbcd" oder "abc capture me bcd" oder auch nur "capture me" aussehen kann.

Oder andersherum: Wenn der Text immer derselbe ist und Sie ihn nicht erfassen, gibt es keinen Grund, Gruppen zu verwenden.

8
Yaro

Sie können die Methoden matcher.start () und matcher.end () verwenden, um die Gruppenpositionen abzurufen. Wenn Sie diese Position verwenden, können Sie jeden Text einfach ersetzen.

1
ydanneg

ersetzen Sie die Passwortfelder aus der Eingabe:

{"_csrf":["9d90c85f-ac73-4b15-ad08-ebaa3fa4a005"],"originPassword":["uaas"],"newPassword":["uaas"],"confirmPassword":["uaas"]}



  private static final Pattern PATTERN = Pattern.compile(".*?password.*?\":\\[\"(.*?)\"\\](,\"|}$)", Pattern.CASE_INSENSITIVE);

  private static String replacePassword(String input, String replacement) {
    Matcher m = PATTERN.matcher(input);
    StringBuffer sb = new StringBuffer();
    while (m.find()) {
      Matcher m2 = PATTERN.matcher(m.group(0));
      if (m2.find()) {
        StringBuilder stringBuilder = new StringBuilder(m2.group(0));
        String result = stringBuilder.replace(m2.start(1), m2.end(1), replacement).toString();
        m.appendReplacement(sb, result);
      }
    }
    m.appendTail(sb);
    return sb.toString();
  }

  @Test
  public void test1() {
    String input = "{\"_csrf\":[\"9d90c85f-ac73-4b15-ad08-ebaa3fa4a005\"],\"originPassword\":[\"123\"],\"newPassword\":[\"456\"],\"confirmPassword\":[\"456\"]}";
    String expected = "{\"_csrf\":[\"9d90c85f-ac73-4b15-ad08-ebaa3fa4a005\"],\"originPassword\":[\"**\"],\"newPassword\":[\"**\"],\"confirmPassword\":[\"**\"]}";
    Assert.assertEquals(expected, replacePassword(input, "**"));
  }
0
whimmy

Hier ist eine andere Lösung, die auch das Ersetzen einer einzelnen Gruppe in mehreren Übereinstimmungen ermöglicht. Sie verwendet Stapel, um die Ausführungsreihenfolge umzukehren, sodass die Zeichenfolgenoperation sicher ausgeführt werden kann.

private static void demo () {

    final String sourceString = "hello world!";

    final String regex = "(hello) (world)(!)";
    final Pattern pattern = Pattern.compile(regex);

    String result = replaceTextOfMatchGroup(sourceString, pattern, 2, world -> world.toUpperCase());
    System.out.println(result);  // output: hello WORLD!
}

public static String replaceTextOfMatchGroup(String sourceString, Pattern pattern, int groupToReplace, Function<String,String> replaceStrategy) {
    Stack<Integer> startPositions = new Stack<>();
    Stack<Integer> endPositions = new Stack<>();
    Matcher matcher = pattern.matcher(sourceString);

    while (matcher.find()) {
        startPositions.Push(matcher.start(groupToReplace));
        endPositions.Push(matcher.end(groupToReplace));
    }
    StringBuilder sb = new StringBuilder(sourceString);
    while (! startPositions.isEmpty()) {
        int start = startPositions.pop();
        int end = endPositions.pop();
        if (start >= 0 && end >= 0) {
            sb.replace(start, end, replaceStrategy.apply(sourceString.substring(start, end)));
        }
    }
    return sb.toString();       
}
0
Jonas_Hess