1
1
/*
2
- * Copyright (c) 1999, 2022 , Oracle and/or its affiliates. All rights reserved.
2
+ * Copyright (c) 1999, 2023 , Oracle and/or its affiliates. All rights reserved.
3
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
4
*
5
5
* This code is free software; you can redistribute it and/or modify it
25
25
26
26
package java .util .regex ;
27
27
28
+ import java .io .IOException ;
28
29
import java .util .ConcurrentModificationException ;
29
30
import java .util .Iterator ;
30
31
import java .util .Map ;
@@ -917,12 +918,16 @@ public static String quoteReplacement(String s) {
917
918
*/
918
919
public Matcher appendReplacement (StringBuffer sb , String replacement ) {
919
920
checkMatch ();
920
- StringBuilder result = new StringBuilder ();
921
- appendExpandedReplacement (replacement , result );
922
- // Append the intervening text
923
- sb .append (text , lastAppendPosition , first );
924
- // Append the match substitution
925
- sb .append (result );
921
+ int curLen = sb .length ();
922
+ try {
923
+ // Append the intervening text
924
+ sb .append (text , lastAppendPosition , first );
925
+ // Append the match substitution
926
+ appendExpandedReplacement (sb , replacement );
927
+ } catch (IllegalArgumentException e ) {
928
+ sb .setLength (curLen );
929
+ throw e ;
930
+ }
926
931
lastAppendPosition = last ;
927
932
modCount ++;
928
933
return this ;
@@ -1004,14 +1009,17 @@ public Matcher appendReplacement(StringBuffer sb, String replacement) {
1004
1009
* @since 9
1005
1010
*/
1006
1011
public Matcher appendReplacement (StringBuilder sb , String replacement ) {
1007
- // If no match, return error
1008
1012
checkMatch ();
1009
- StringBuilder result = new StringBuilder ();
1010
- appendExpandedReplacement (replacement , result );
1011
- // Append the intervening text
1012
- sb .append (text , lastAppendPosition , first );
1013
- // Append the match substitution
1014
- sb .append (result );
1013
+ int curLen = sb .length ();
1014
+ try {
1015
+ // Append the intervening text
1016
+ sb .append (text , lastAppendPosition , first );
1017
+ // Append the match substitution
1018
+ appendExpandedReplacement (sb , replacement );
1019
+ } catch (IllegalArgumentException e ) {
1020
+ sb .setLength (curLen );
1021
+ throw e ;
1022
+ }
1015
1023
lastAppendPosition = last ;
1016
1024
modCount ++;
1017
1025
return this ;
@@ -1021,93 +1029,94 @@ public Matcher appendReplacement(StringBuilder sb, String replacement) {
1021
1029
* Processes replacement string to replace group references with
1022
1030
* groups.
1023
1031
*/
1024
- private StringBuilder appendExpandedReplacement (
1025
- String replacement , StringBuilder result ) {
1026
- int cursor = 0 ;
1027
- while (cursor < replacement .length ()) {
1028
- char nextChar = replacement .charAt (cursor );
1029
- if (nextChar == '\\' ) {
1030
- cursor ++;
1031
- if (cursor == replacement .length ())
1032
- throw new IllegalArgumentException (
1033
- "character to be escaped is missing" );
1034
- nextChar = replacement .charAt (cursor );
1035
- result .append (nextChar );
1036
- cursor ++;
1037
- } else if (nextChar == '$' ) {
1038
- // Skip past $
1039
- cursor ++;
1040
- // Throw IAE if this "$" is the last character in replacement
1041
- if (cursor == replacement .length ())
1042
- throw new IllegalArgumentException (
1043
- "Illegal group reference: group index is missing" );
1044
- nextChar = replacement .charAt (cursor );
1045
- int refNum = -1 ;
1046
- if (nextChar == '{' ) {
1032
+ private void appendExpandedReplacement (Appendable app , String replacement ) {
1033
+ try {
1034
+ int cursor = 0 ;
1035
+ while (cursor < replacement .length ()) {
1036
+ char nextChar = replacement .charAt (cursor );
1037
+ if (nextChar == '\\' ) {
1047
1038
cursor ++;
1048
- StringBuilder gsb = new StringBuilder ();
1049
- while (cursor < replacement .length ()) {
1050
- nextChar = replacement .charAt (cursor );
1051
- if (ASCII .isLower (nextChar ) ||
1052
- ASCII .isUpper (nextChar ) ||
1053
- ASCII .isDigit (nextChar )) {
1054
- gsb .append (nextChar );
1055
- cursor ++;
1056
- } else {
1057
- break ;
1058
- }
1059
- }
1060
- if (gsb .length () == 0 )
1061
- throw new IllegalArgumentException (
1062
- "named capturing group has 0 length name" );
1063
- if (nextChar != '}' )
1064
- throw new IllegalArgumentException (
1065
- "named capturing group is missing trailing '}'" );
1066
- String gname = gsb .toString ();
1067
- if (ASCII .isDigit (gname .charAt (0 )))
1068
- throw new IllegalArgumentException (
1069
- "capturing group name {" + gname +
1070
- "} starts with digit character" );
1071
- if (!namedGroups ().containsKey (gname ))
1039
+ if (cursor == replacement .length ())
1072
1040
throw new IllegalArgumentException (
1073
- "No group with name {" + gname + "}" );
1074
- refNum = namedGroups ().get (gname );
1041
+ "character to be escaped is missing" );
1042
+ nextChar = replacement .charAt (cursor );
1043
+ app .append (nextChar );
1075
1044
cursor ++;
1076
- } else {
1077
- // The first number is always a group
1078
- refNum = nextChar - '0' ;
1079
- if ((refNum < 0 ) || (refNum > 9 ))
1080
- throw new IllegalArgumentException (
1081
- "Illegal group reference" );
1045
+ } else if (nextChar == '$' ) {
1046
+ // Skip past $
1082
1047
cursor ++;
1083
- // Capture the largest legal group string
1084
- boolean done = false ;
1085
- while (!done ) {
1086
- if (cursor >= replacement .length ()) {
1087
- break ;
1088
- }
1089
- int nextDigit = replacement .charAt (cursor ) - '0' ;
1090
- if ((nextDigit < 0 ) || (nextDigit > 9 )) { // not a number
1091
- break ;
1048
+ // Throw IAE if this "$" is the last character in replacement
1049
+ if (cursor == replacement .length ())
1050
+ throw new IllegalArgumentException (
1051
+ "Illegal group reference: group index is missing" );
1052
+ nextChar = replacement .charAt (cursor );
1053
+ int refNum = -1 ;
1054
+ if (nextChar == '{' ) {
1055
+ cursor ++;
1056
+ int begin = cursor ;
1057
+ while (cursor < replacement .length ()) {
1058
+ nextChar = replacement .charAt (cursor );
1059
+ if (ASCII .isLower (nextChar ) ||
1060
+ ASCII .isUpper (nextChar ) ||
1061
+ ASCII .isDigit (nextChar )) {
1062
+ cursor ++;
1063
+ } else {
1064
+ break ;
1065
+ }
1092
1066
}
1093
- int newRefNum = (refNum * 10 ) + nextDigit ;
1094
- if (groupCount () < newRefNum ) {
1095
- done = true ;
1096
- } else {
1097
- refNum = newRefNum ;
1098
- cursor ++;
1067
+ if (begin == cursor )
1068
+ throw new IllegalArgumentException (
1069
+ "named capturing group has 0 length name" );
1070
+ if (nextChar != '}' )
1071
+ throw new IllegalArgumentException (
1072
+ "named capturing group is missing trailing '}'" );
1073
+ String gname = replacement .substring (begin , cursor );
1074
+ if (ASCII .isDigit (gname .charAt (0 )))
1075
+ throw new IllegalArgumentException (
1076
+ "capturing group name {" + gname +
1077
+ "} starts with digit character" );
1078
+ if (!namedGroups ().containsKey (gname ))
1079
+ throw new IllegalArgumentException (
1080
+ "No group with name {" + gname + "}" );
1081
+ refNum = namedGroups ().get (gname );
1082
+ cursor ++;
1083
+ } else {
1084
+ // The first number is always a group
1085
+ refNum = nextChar - '0' ;
1086
+ if ((refNum < 0 ) || (refNum > 9 ))
1087
+ throw new IllegalArgumentException (
1088
+ "Illegal group reference" );
1089
+ cursor ++;
1090
+ // Capture the largest legal group string
1091
+ boolean done = false ;
1092
+ while (!done ) {
1093
+ if (cursor >= replacement .length ()) {
1094
+ break ;
1095
+ }
1096
+ int nextDigit = replacement .charAt (cursor ) - '0' ;
1097
+ if ((nextDigit < 0 ) || (nextDigit > 9 )) { // not a number
1098
+ break ;
1099
+ }
1100
+ int newRefNum = (refNum * 10 ) + nextDigit ;
1101
+ if (groupCount () < newRefNum ) {
1102
+ done = true ;
1103
+ } else {
1104
+ refNum = newRefNum ;
1105
+ cursor ++;
1106
+ }
1099
1107
}
1100
1108
}
1109
+ // Append group
1110
+ if (start (refNum ) != -1 && end (refNum ) != -1 )
1111
+ app .append (text , start (refNum ), end (refNum ));
1112
+ } else {
1113
+ app .append (nextChar );
1114
+ cursor ++;
1101
1115
}
1102
- // Append group
1103
- if (start (refNum ) != -1 && end (refNum ) != -1 )
1104
- result .append (text , start (refNum ), end (refNum ));
1105
- } else {
1106
- result .append (nextChar );
1107
- cursor ++;
1108
1116
}
1117
+ } catch (IOException e ) { // cannot happen on String[Buffer|Builder]
1118
+ throw new AssertionError (e .getMessage ());
1109
1119
}
1110
- return result ;
1111
1120
}
1112
1121
1113
1122
/**
0 commit comments