2

I hope to replace two substring in the String s, so I write the following code. I think the efficiency is too low in my code when S is a huge string.

Can I replace multiple substring of a string at one time? or is there a better way to replace string?

Added:

I hope to find a way which can replace substring quickly!

   String s="This %ToolBar% is a %Content%";

   s=s.replace("%ToolBar%","Edit ToolBar");
   s=s.replace("%Content%","made by Paul");
HelloCW
  • 843
  • 22
  • 125
  • 310
  • 1
    You can always chain them like `s=s.replace("%ToolBar%","Edit ToolBar").replace("%Content%","made by Paul");` or see this question: https://stackoverflow.com/questions/7658568/most-efficient-way-to-use-replace-multiple-words-in-a-string – Andrew Brooke Jul 29 '16 at 01:48
  • how about regular expression? – L. Swifter Jul 29 '16 at 01:57
  • 1
    I look at your code and I can understand it immediately, and would be able to maintain this code is 1 years time. Why do you want to change that? – Scary Wombat Jul 29 '16 at 01:58
  • Thanks! To Andrew Brooke: When string is huge, is your way s=s.replace("%ToolBar%","Edit ToolBar").replace("%Content%","made by Paul") more faster than mine? – HelloCW Jul 29 '16 at 02:10
  • @HelloCW No, it just uses method chaining for the same result. Each `replace()` call still searches the entire string. – Andreas Jul 29 '16 at 02:11

1 Answers1

4

If you want to only perform one search of s, you can either do your own indexOf() loop, or use a regular expression replacement loop.

Here is an example of using a regular expression replacement loop, which uses the appendReplacement() and appendTail() methods to build the result.

To eliminate the need for doing a string comparison to figure out which keyword was found, each keyword is made a capturing group, so existence of keyword can be quickly checked using start(int group).

String s = "This %ToolBar% is a %Content%";

StringBuffer buf = new StringBuffer();
Matcher m = Pattern.compile("%(?:(ToolBar)|(Content))%").matcher(s);
while (m.find()) {
    if (m.start(1) != -1)
        m.appendReplacement(buf, "Edit ToolBar");
    else if (m.start(2) != -1)
        m.appendReplacement(buf, "made by Paul");
}
m.appendTail(buf);
System.out.println(buf.toString()); // prints: This Edit ToolBar is a made by Paul

The above runs in Java 1.4 and later. In Java 9+, you can use StringBuilder instead of StringBuffer, or you can do it with a lambda expression using replaceAll​():

String s = "This %ToolBar% is a %Content%";

String result = Pattern.compile("%(?:(ToolBar)|(Content))%").matcher(s)
        .replaceAll(m -> (m.start(1) != -1 ? "Edit ToolBar" : "made by Paul"));
System.out.println(result); // prints: This Edit ToolBar is a made by Paul

A more dynamic version can be seen in this other answer.

Andreas
  • 154,647
  • 11
  • 152
  • 247
  • Thanks! To Andreas: is your way very fastest way to replace substring? – HelloCW Jul 29 '16 at 02:13
  • `indexOf()` loop, if done correctly, may be slightly faster. This is simpler and still only searches your very long input once, which is the main concern. – Andreas Jul 29 '16 at 02:15
  • Since Java 9 we can also use Matcher#replaceAll(Function replacer). This allows us to skip explicit buffer and loop and allows us to write code like `String result = Pattern .compile("%(?:(ToolBar)|(Content))%") .matcher(s) .replaceAll(m -> (m.start(1) != -1) ? "Edit ToolBar": "made by Paul");` – Pshemo Jun 13 '20 at 19:22
  • @Pshemo Added to answer. Thanks. – Andreas Jun 13 '20 at 22:39