java - vogella - rex101




Posso sostituire i gruppi nella regex di Java? (4)

È possibile utilizzare i metodi matcher.start () e matcher.end () per ottenere le posizioni del gruppo. Quindi, usando queste posizioni, puoi facilmente sostituire qualsiasi testo.

Ho questo codice, e voglio sapere, se posso sostituire solo i gruppi (non tutti i pattern) nella regex di Java. Codice:

 //...
 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.

    }

Aggiungi un terzo gruppo aggiungendo parenti in giro .* , Quindi sostituisci la "number" + m.group(2) + "1" con "number" + m.group(2) + "1" . per esempio:

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

Mi spiace battere un cavallo morto, ma è strano che nessuno lo abbia sottolineato - "Sì, puoi farlo, ma questo è l'opposto di come usi i gruppi catturati nella vita reale".

Se si utilizza Regex come deve essere usato, la soluzione è semplice come questa:

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

O come giustamente sottolineato da shmosel di seguito,

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

... poiché nella tua espressione regolare non c'è nessuna buona ragione per raggruppare i decimali.

Di solito non usi i gruppi di cattura sulle parti della stringa che vuoi scartare , li usi sulla parte della stringa che vuoi conservare .

Se vuoi davvero i gruppi che vuoi sostituire, quello che probabilmente preferisci è un motore di template (es. Baffi, ejs, StringTemplate, ...).

A parte i curiosi, anche i gruppi non-catturanti nelle regex sono lì solo per il caso in cui il motore regex ha bisogno di riconoscere e saltare il testo variabile. Ad esempio, in

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

ne hai bisogno se il tuo input può somigliare a "abcabc capture me bcdbcd" o "abc capture me bcd" o anche solo a "catturarmi".

O per dirla in un altro modo: se il testo è sempre lo stesso e non lo si cattura, non vi è alcun motivo per utilizzare i gruppi.


Potresti usare Matcher#start(group) e Matcher#end(group) per creare un metodo di sostituzione generico:

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, "!!!"));
}

Controlla la demo online qui .







regex-group