Mam ten kod i chcę wiedzieć, czy mogę zamienić tylko grupy (nie wszystkie wzorce) w wyrażeniach regularnych Java. Kod:
//...
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.
}
java
regex
replace
regex-group
wokena
źródło
źródło
Odpowiedzi:
Użyj
$n
(gdzie n jest cyfrą), aby odwołać się do przechwyconych podsekwencji w programiereplaceFirst(...)
. Zakładam, że chciałeś zamienić pierwszą grupę na literalny ciąg znaków „liczba”, a drugą grupę na wartość pierwszej grupy.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 }
Rozważ
(\D+)
drugą grupę zamiast(.*)
.*
jest chciwym dopasowaniem i na początku pochłonie ostatnią cyfrę. Następnie dopasowujący będzie musiał wycofać się, gdy zda sobie sprawę, że finał(\d)
nie ma nic do dopasowania, zanim będzie mógł dopasować się do ostatniej cyfry.źródło
m.replaceFirst("number $2$1");
Powinno byćm.replaceFirst("number $3$1");
Możesz użyć
Matcher#start(group)
iMatcher#end(group)
zbudować ogólną metodę zamiany: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, "!!!")); }
Sprawdź demo online tutaj .
źródło
Przepraszam, że biłem martwego konia, ale to trochę dziwne, że nikt tego nie zauważył - „Tak, możesz, ale to jest przeciwieństwo tego, jak używasz chwytania grup w prawdziwym życiu”.
Jeśli używasz Regex w sposób, w jaki ma być używany, rozwiązanie jest tak proste:
"6 example input 4".replaceAll("(?:\\d)(.*)(?:\\d)", "number$11");
Lub jak słusznie wskazano w shmosel poniżej,
"6 example input 4".replaceAll("\d(.*)\d", "number$11");
... ponieważ w Twoim wyrażeniu regularnym nie ma żadnego powodu, aby grupować ułamki dziesiętne.
Zwykle nie używasz grup przechwytywania na częściach łańcucha, które chcesz odrzucić , używasz ich na części łańcucha, którą chcesz zachować .
Jeśli naprawdę potrzebujesz grup, które chcesz zastąpić, prawdopodobnie zamiast tego potrzebujesz silnika szablonów (np. Wąsy, ejs, StringTemplate, ...).
Na marginesie dla ciekawskich, nawet nieprzechwytywane grupy w wyrażeniach regularnych są dostępne tylko na wypadek, gdyby silnik wyrażeń regularnych wymagał od nich rozpoznawania i pomijania tekstu zmiennego. Na przykład w
potrzebujesz ich, jeśli dane wejściowe mogą wyglądać na „ abcabc złap mnie bcdbcd” lub „abc capture me bcd” lub po prostu „capture me”.
Albo odwrotnie: jeśli tekst jest zawsze taki sam, a go nie przechwytujesz, nie ma żadnego powodu, aby używać grup.
źródło
\d(.*)\d
wystarczy.$11
tutaj. Dlaczego 11?Dodaj trzecią grupę, dodając pareny wokół
.*
, a następnie zamień podciąg na"number" + m.group(2) + "1"
. na przykład:String output = m.replaceFirst("number" + m.group(2) + "1");
źródło
"number$21"
działa i"number" + m.group(2) + "1"
nie działa.number$21
że zastąpi grupę 21, a nie grupę 2 + ciąg „1”.Możesz użyć metod matcher.start () i matcher.end (), aby uzyskać pozycje grupowe. Dzięki tym pozycjom możesz łatwo zastąpić dowolny tekst.
źródło
zastąp pola hasła z pola wejściowego:
{"_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, "**")); }
źródło
Oto inne rozwiązanie, które umożliwia również zastąpienie jednej grupy w wielu meczach. Używa stosów do odwrócenia kolejności wykonywania, więc operacja na łańcuchu może być bezpiecznie wykonana.
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(); }
źródło