8291598: Matcher.appendReplacement should not create new StringBuilder instances

Reviewed-by: rriggs
This commit is contained in:
Raffaello Giulietti 2023-03-28 17:55:23 +00:00
parent 1683a63a7d
commit ca745cb426

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,6 +25,7 @@
package java.util.regex;
import java.io.IOException;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.Map;
@ -917,12 +918,16 @@ public final class Matcher implements MatchResult {
*/
public Matcher appendReplacement(StringBuffer sb, String replacement) {
checkMatch();
StringBuilder result = new StringBuilder();
appendExpandedReplacement(replacement, result);
int curLen = sb.length();
try {
// Append the intervening text
sb.append(text, lastAppendPosition, first);
// Append the match substitution
sb.append(result);
appendExpandedReplacement(sb, replacement);
} catch (IllegalArgumentException e) {
sb.setLength(curLen);
throw e;
}
lastAppendPosition = last;
modCount++;
return this;
@ -1004,14 +1009,17 @@ public final class Matcher implements MatchResult {
* @since 9
*/
public Matcher appendReplacement(StringBuilder sb, String replacement) {
// If no match, return error
checkMatch();
StringBuilder result = new StringBuilder();
appendExpandedReplacement(replacement, result);
int curLen = sb.length();
try {
// Append the intervening text
sb.append(text, lastAppendPosition, first);
// Append the match substitution
sb.append(result);
appendExpandedReplacement(sb, replacement);
} catch (IllegalArgumentException e) {
sb.setLength(curLen);
throw e;
}
lastAppendPosition = last;
modCount++;
return this;
@ -1021,8 +1029,8 @@ public final class Matcher implements MatchResult {
* Processes replacement string to replace group references with
* groups.
*/
private StringBuilder appendExpandedReplacement(
String replacement, StringBuilder result) {
private void appendExpandedReplacement(Appendable app, String replacement) {
try {
int cursor = 0;
while (cursor < replacement.length()) {
char nextChar = replacement.charAt(cursor);
@ -1032,7 +1040,7 @@ public final class Matcher implements MatchResult {
throw new IllegalArgumentException(
"character to be escaped is missing");
nextChar = replacement.charAt(cursor);
result.append(nextChar);
app.append(nextChar);
cursor++;
} else if (nextChar == '$') {
// Skip past $
@ -1045,25 +1053,24 @@ public final class Matcher implements MatchResult {
int refNum = -1;
if (nextChar == '{') {
cursor++;
StringBuilder gsb = new StringBuilder();
int begin = cursor;
while (cursor < replacement.length()) {
nextChar = replacement.charAt(cursor);
if (ASCII.isLower(nextChar) ||
ASCII.isUpper(nextChar) ||
ASCII.isDigit(nextChar)) {
gsb.append(nextChar);
cursor++;
} else {
break;
}
}
if (gsb.length() == 0)
if (begin == cursor)
throw new IllegalArgumentException(
"named capturing group has 0 length name");
if (nextChar != '}')
throw new IllegalArgumentException(
"named capturing group is missing trailing '}'");
String gname = gsb.toString();
String gname = replacement.substring(begin, cursor);
if (ASCII.isDigit(gname.charAt(0)))
throw new IllegalArgumentException(
"capturing group name {" + gname +
@ -1101,13 +1108,15 @@ public final class Matcher implements MatchResult {
}
// Append group
if (start(refNum) != -1 && end(refNum) != -1)
result.append(text, start(refNum), end(refNum));
app.append(text, start(refNum), end(refNum));
} else {
result.append(nextChar);
app.append(nextChar);
cursor++;
}
}
return result;
} catch (IOException e) { // cannot happen on String[Buffer|Builder]
throw new AssertionError(e.getMessage());
}
}
/**