5

I would like to replace some texts in StringBuilder. How to do this?

In this code I got java.lang.StringIndexOutOfBoundsException at line with matcher.find():

StringBuilder sb = new StringBuilder(input);
Pattern pattern = Pattern.compile(str_pattern);
Matcher matcher = pattern.matcher(sb);
while (matcher.find())
  sb.replace(matcher.start(), matcher.end(), "x"); 
bltc
  • 371
  • 1
  • 3
  • 9

6 Answers6

4

Lets have a StringBuilder w/ 50 total length and you change the first 20chars to 'x'. So the StringBuilder is shrunk by 19, right - however the initial input pattern.matcher(sb) is not altered, so in the end StringIndexOutOfBoundsException.

bestsss
  • 11,796
  • 3
  • 53
  • 63
2

I've solved this by adding matcher.reset():

    while (matcher.find())
    {
        sb.replace(matcher.start(), matcher.end(), "x");
        matcher.reset();
    }
bltc
  • 371
  • 1
  • 3
  • 9
  • 1
    With `str_pattern = "x"` and `input = "x"` you get an endless loop. With `str_pattern = "xx"` and `input = "xxxx"` you get a wrong result (`"x"` instead of `"xx"`). – maaartinus Feb 02 '11 at 10:13
  • Adding matcher.reset() is not working. I'm still getting the same exception. – Sri Nov 27 '12 at 12:59
1

This is already a reported bug and I'm guessing they're currently looking into a fix for it. Read more here.

Community
  • 1
  • 1
evandrix
  • 6,041
  • 4
  • 27
  • 38
1

You shouldn't do it this way. The input to Matcher may be any CharSequence, but the sequence should not change. Matching like you do is like iterating over a Collection while removing elements at the same time, this can't work.

However, maybe there's a solution:

while (matcher.find()) {
    sb.replace(matcher.start(), matcher.end(), "x");
    matcher.region(matcher.start() + "x".length(), sb.length());
}
maaartinus
  • 44,714
  • 32
  • 161
  • 320
0

Maybe:

    int lookIndex = 0;
    while (lookIndex < builder.length() && matcher.find(lookIndex)) {
        lookIndex = matcher.start()+1;
        builder.replace(matcher.start(), matcher.end(), repl);
    }

...?

.find(n) with an integer argument claims to reset the matcher before it starts looking at the specified index. That would work around the issues raised in maartinus comment above.

TV's Frank
  • 782
  • 7
  • 21
0

Another issue with using StringBuidler.replace() is that that one can't handle capturing groups.

TV's Frank
  • 782
  • 7
  • 21