32

At the moment I'm doing

Example:

line.replaceAll(",","").replaceAll("cat","dog").replaceAll("football","rugby");

I think that it ugly. Not sure a better way to do this? Maybe loop through a hashmap?

EDIT:

By efficiency I mean better code style and flexibility

Decrypter
  • 2,784
  • 12
  • 38
  • 57
  • 4
    Is your question about runtime efficiency? Flexibility? Code style? Please clarify. – Mac Oct 05 '11 at 08:31
  • 2
    It may also be a question of correctness, for the replacements made during N passes may be not equivalent to performing replacements of N pairs during a single pass. – Xion Oct 05 '11 at 08:34
  • 2
    Updated question but looking for the code to be styled better and allow flexibility – Decrypter Oct 05 '11 at 08:35
  • 2
    similar question: http://stackoverflow.com/q/1326682/18511 – Kip Oct 05 '16 at 19:43

4 Answers4

23

This functionality is already implemented in Commons Lang's StringUtils class.

StringUtils.replaceEach(String text, String[] searchList, String[] replacementList)
Clint Eastwood
  • 4,995
  • 3
  • 31
  • 27
Mukesh Koshy M
  • 239
  • 2
  • 2
  • 1
    I believe it is not in standard library but rather in Apache Commons [link](https://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/StringUtils.html#replaceEach%28java.lang.String,%20java.lang.String[],%20java.lang.String[]%29) – tkokasih Apr 15 '15 at 08:47
  • New version would be the [`StrSubstitutor`](https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/StrSubstitutor.html) from [Apache Commons Text](https://commons.apache.org/proper/commons-text/). – Andreas Sep 09 '17 at 18:18
  • 1
    StrSubstitutor seems to have a different purpose than a standard replace. – Christopher Schneider Jun 13 '19 at 15:41
22

You can use Matcher.appendReplacement()/appendTail() to build very flexible search-and-replace features.

The example in the JavaDoc looks like this:

Pattern p = Pattern.compile("cat");
Matcher m = p.matcher("one cat two cats in the yard");
StringBuffer sb = new StringBuffer();
while (m.find()) {
    m.appendReplacement(sb, "dog");
}
m.appendTail(sb);
System.out.println(sb.toString());

Now, inside that while loop you can decide yourself what the replacement text is and base that information on the actual content being matched.

For example you could use the pattern (,|cat|football) to match ,, cat or football and decide on the actual replacement based on the actual match inside the loop.

You can make build even more flexible things this way, such as replacing all decimal numbers with hex numbers or similar operations.

It's not as short and simple as your code, but you can build short and simple methods with it.

Joachim Sauer
  • 302,674
  • 57
  • 556
  • 614
  • What if you have hundreds of different words to check? The entire string would have to be scanned for each word, which is very inefficient. – Jack Cole Dec 05 '19 at 22:06
  • @JackCole: no you wouldn't. Check the paragraph talking about the pattern with multiple words. You can still build a single pattern with any number of words. – Joachim Sauer Dec 05 '19 at 22:46
  • Ah, I see now. You could follow up with a Map lookup of that word. I wonder how this performs in comparison to the above answer. – Jack Cole Dec 06 '19 at 00:12
  • "For example you could use the pattern (,|cat|football) to match ,, cat or football and decide on the actual replacement based on the actual match inside the loop." Are you saying I could replace ',' with a '.' and 'cat' with 'dog' in one while loop? How does this look? – Blaisem Apr 14 '23 at 08:06
  • @Blaisem: exactly, that's what you can do. Inside the `while` loop simply inspect the return value of `m.group()` and the call àppendReplacement` with different second parameters based on what is returned. – Joachim Sauer Apr 14 '23 at 11:53
4

Apart from that the actual replace is internally converted to a regex I think that approach is fine. A non-regex implementation can be found in StringUtils.replace(..) .

Looking at what alternatives there might be, you still need something to identify pairs of strings. This could look like:

MultiReplaceUtil.replaceAll{line, 
       {",", ""}, {"cat", "dog"}, {"football", "rugby"}};

or perhaps

MapReplaceUtil(String s, Map<String, String> replacementMap);

or even

ArrayReplaceUtil(String s, String[] target, String[] replacement);

neither of which seems more intuitive to me in terms of coding practice.

Johan Sjöberg
  • 47,929
  • 21
  • 130
  • 148
2

For Scala lovers:

"cat".r.replaceAllIn("one cat two cats in the yard", m => "dog")

With m you can even parameterize your replacement.

Waldemar Wosiński
  • 1,490
  • 17
  • 28