Java replace all with group

Search and replace with regular expressions

It is possible to perform search and replace operations on strings in Java using regular expressions. The Java String and Matcher classes offer relatively simple methods for matching and search/replacing strings which can bring the benefit of string matching optimisations that could be cumbersome to implement from scratch. The complexity of using these methods depends how much flexibility you need:

  • to find and replace instance of one fixed substring with another, we can use String.replaceAll()— we just need to take a little care (see below);
  • to search for and replace instances of a regular expression in a string with a fixed string, then we can generally use a simple call to String.replaceAll();
  • if the replacement string isn’t fixed, then you can use replaceAll() with a lambda expression to specify a dynamic replacement and/or use the Java Pattern and Matcher classes explicitly, giving complete control over the find and replace operation.

Replacing one «fixed» substring with another

This is the «simplest» form of search and replace. We want to find exact instances of a specific subtring and replace them with another given substring. To do so, we can call replaceAll() on the String, but we need to put Pattern.quote() around the substring we are searching for. For example, this will replace all instances of the substring «1+» with «one plus»:

str = str.replaceAll(Pattern.quote("1+"), "one plus");

If you are familiar with regular expressions, then you will know that a plus sign normally has a special meaning. But provided you remember to put Pattern.quote() around the first string, we can use replaceAll() as a simple search and replace call. (If the replacement substring contains a dollar sign or backslash, then we also need to use Matcher.quoteReplacement(): see below.)

Replacing substrings with a fixed string

If you simply want to replace all instances of a given expression within a Java string with another fixed string, then things are fairly straightforward. For example, the following replaces all instances of digits with a letter X:

We’ll see in the next section that we should be careful about passing «raw» strings as the second paramter, since certain characters in this string actually have special meanings.

Читайте также:  Curl php для чайников

Replacing with a sub-part of the matched portion

In the replacement string, we can refer to captured groups from the regular expression. For example, the following expression removes instances of the HTML ‘bold’ tag from a string, but leaves the text inside the tag intact:

In the expression ([^<]*), we capture the text between the open and close tags as group 1. Then, in the replacement string, we can refer to the text of group 1 with the expression $1. (The second group would be $2 etc.)

Including a dollar sign or backslashes in the replacement string

To actually include a dollar sign or backslash in the replacement string, we need to put another backslash before the dollar symbol or backslash to «escape» it. remembering that within a string literal, a single backslash also needs to be doubled up! For example:

The static method Matcher.quoteReplacement() will replace instances of dollar signs and backslashes in a given string with the correct form to allow them to be used as literal replacements:

str = str.replaceAll("USD", Matcher.quoteReplacement("$"));
  • If there is a chance that the replacement string will include a dollar sign or a backslash character, then you should wrap it in Matcher.quoteReplacement().

Further information: more flexible find and replacement operations

  • the replaceAll() method can be used with a lambda expression: see the accompanying page and example of using replaceAll() with a lambda expression;
  • Matcher.find() method can be used to provide further control over the operation.

If you enjoy this Java programming article, please share with friends and colleagues. Follow the author on Twitter for the latest news and rants. Follow @BitterCoffey

Editorial page content written by Neil Coffey. Copyright © Javamex UK 2021. All rights reserved.

Источник

Can I replace groups in Java regex?

I have this code, and I want to know, if I can replace only groups (not all pattern) in Java regex. Code:

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

Solution 1 — Java

Use $n (where n is a digit) to refer to captured subsequences in replaceFirst(. ) . I’m assuming you wanted to replace the first group with the literal string «number» and the second group with the value of the first group.

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 > 

Consider (\D+) for the second group instead of (.*) . * is a greedy matcher, and will at first consume the last digit. The matcher will then have to backtrack when it realizes the final (\d) has nothing to match, before it can match to the final digit.

Читайте также:  Html table td valign middle

Solution 2 — Java

You could use Matcher#start(group) and Matcher#end(group) to build a generic replacement method:

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]+)(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, ". ")); > 

Solution 3 — Java

Sorry to beat a dead horse, but it is kind-of weird that no-one pointed this out — «Yes you can, but this is the opposite of how you use capturing groups in real life».

If you use Regex the way it is meant to be used, the solution is as simple as this:

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

Or as rightfully pointed out by shmosel below,

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

. since in your regex there is no good reason to group the decimals at all.

You don’t usually use capturing groups on the parts of the string you want to discard, you use them on the part of the string you want to keep.

If you really want groups that you want to replace, what you probably want instead is a templating engine (e.g. moustache, ejs, StringTemplate, . ).

As an aside for the curious, even non-capturing groups in regexes are just there for the case that the regex engine needs them to recognize and skip variable text. For example, in

Читайте также:  Check if variable is none python

you need them if your input can look either like «abcabccapture mebcdbcd» or «abccapture mebcd» or even just «capture me».

Or to put it the other way around: if the text is always the same, and you don’t capture it, there is no reason to use groups at all.

Solution 4 — Java

You can use matcher.start() and matcher.end() methods to get the group positions. So using this positions you can easily replace any text.

Solution 5 — Java

replace the password fields from the input:

"_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, "**")); > 

Solution 6 — Java

Here is a different solution, that also allows the replacement of a single group in multiple matches. It uses stacks to reverse the execution order, so the string operation can be safely executed.

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 replaceStrategy) < StackstartPositions = new Stack<>(); Stack 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(); > 

Источник

Оцените статью