957 * m.appendReplacement(sb, "dog");
958 * }
959 * m.appendTail(sb);
960 * System.out.println(sb.toString());</pre></blockquote>
961 *
962 * @param sb
963 * The target string builder
964 * @param replacement
965 * The replacement string
966 * @return This matcher
967 *
968 * @throws IllegalStateException
969 * If no match has yet been attempted,
970 * or if the previous match operation failed
971 * @throws IllegalArgumentException
972 * If the replacement string refers to a named-capturing
973 * group that does not exist in the pattern
974 * @throws IndexOutOfBoundsException
975 * If the replacement string refers to a capturing group
976 * that does not exist in the pattern
977 * @since 1.9
978 */
979 public Matcher appendReplacement(StringBuilder sb, String replacement) {
980 // If no match, return error
981 if (first < 0)
982 throw new IllegalStateException("No match available");
983 StringBuilder result = new StringBuilder();
984 appendExpandedReplacement(replacement, result);
985 // Append the intervening text
986 sb.append(text, lastAppendPosition, first);
987 // Append the match substitution
988 sb.append(result);
989 lastAppendPosition = last;
990 modCount++;
991 return this;
992 }
993
994 /**
995 * Processes replacement string to replace group references with
996 * groups.
997 */
1100 */
1101 public StringBuffer appendTail(StringBuffer sb) {
1102 sb.append(text, lastAppendPosition, getTextLength());
1103 return sb;
1104 }
1105
1106 /**
1107 * Implements a terminal append-and-replace step.
1108 *
1109 * <p> This method reads characters from the input sequence, starting at
1110 * the append position, and appends them to the given string builder. It is
1111 * intended to be invoked after one or more invocations of the {@link
1112 * #appendReplacement appendReplacement} method in order to copy the
1113 * remainder of the input sequence. </p>
1114 *
1115 * @param sb
1116 * The target string builder
1117 *
1118 * @return The target string builder
1119 *
1120 * @since 1.9
1121 */
1122 public StringBuilder appendTail(StringBuilder sb) {
1123 sb.append(text, lastAppendPosition, getTextLength());
1124 return sb;
1125 }
1126
1127 /**
1128 * Replaces every subsequence of the input sequence that matches the
1129 * pattern with the given replacement string.
1130 *
1131 * <p> This method first resets this matcher. It then scans the input
1132 * sequence looking for matches of the pattern. Characters that are not
1133 * part of any match are appended directly to the result string; each match
1134 * is replaced in the result by the replacement string. The replacement
1135 * string may contain references to captured subsequences as in the {@link
1136 * #appendReplacement appendReplacement} method.
1137 *
1138 * <p> Note that backslashes ({@code \}) and dollar signs ({@code $}) in
1139 * the replacement string may cause the results to be different than if it
1140 * were being treated as a literal replacement string. Dollar signs may be
1212 * <p> The state of each match result passed to the replacer function is
1213 * guaranteed to be constant only for the duration of the replacer function
1214 * call and only if the replacer function does not modify this matcher's
1215 * state.
1216 *
1217 * @implNote
1218 * This implementation applies the replacer function to this matcher, which
1219 * is an instance of {@code MatchResult}.
1220 *
1221 * @param replacer
1222 * The function to be applied to the match result of this matcher
1223 * that returns a replacement string.
1224 * @return The string constructed by replacing each matching subsequence
1225 * with the result of applying the replacer function to that
1226 * matched subsequence, substituting captured subsequences as
1227 * needed.
1228 * @throws NullPointerException if the replacer function is null
1229 * @throws ConcurrentModificationException if it is detected, on a
1230 * best-effort basis, that the replacer function modified this
1231 * matcher's state
1232 * @since 1.9
1233 */
1234 public String replaceAll(Function<MatchResult, String> replacer) {
1235 Objects.requireNonNull(replacer);
1236 reset();
1237 boolean result = find();
1238 if (result) {
1239 StringBuilder sb = new StringBuilder();
1240 do {
1241 int ec = modCount;
1242 String replacement = replacer.apply(this);
1243 if (ec != modCount)
1244 throw new ConcurrentModificationException();
1245 appendReplacement(sb, replacement);
1246 result = find();
1247 } while (result);
1248 appendTail(sb);
1249 return sb.toString();
1250 }
1251 return text.toString();
1252 }
1256 * sequence that matches the pattern. The match results occur in the
1257 * same order as the matching subsequences in the input sequence.
1258 *
1259 * <p> Each match result is produced as if by {@link #toMatchResult()}.
1260 *
1261 * <p> This method does not reset this matcher. Matching starts on
1262 * initiation of the terminal stream operation either at the beginning of
1263 * this matcher's region, or, if the matcher has not since been reset, at
1264 * the first character not matched by a previous match.
1265 *
1266 * <p> If the matcher is to be used for further matching operations after
1267 * the terminal stream operation completes then it should be first reset.
1268 *
1269 * <p> This matcher's state should not be modified during execution of the
1270 * returned stream's pipeline. The returned stream's source
1271 * {@code Spliterator} is <em>fail-fast</em> and will, on a best-effort
1272 * basis, throw a {@link java.util.ConcurrentModificationException} if such
1273 * modification is detected.
1274 *
1275 * @return a sequential stream of match results.
1276 * @since 1.9
1277 */
1278 public Stream<MatchResult> results() {
1279 class MatchResultIterator implements Iterator<MatchResult> {
1280 // -ve for call to find, 0 for not found, 1 for found
1281 int state = -1;
1282 // State for concurrent modification checking
1283 // -1 for uninitialized
1284 int expectedCount = -1;
1285 // The input sequence as a string, set once only after first find
1286 // Avoids repeated conversion from CharSequence for each match
1287 String textAsString;
1288
1289 @Override
1290 public MatchResult next() {
1291 if (expectedCount >= 0 && expectedCount != modCount)
1292 throw new ConcurrentModificationException();
1293
1294 if (!hasNext())
1295 throw new NoSuchElementException();
1296
1434 * <p> The state of the match result passed to the replacer function is
1435 * guaranteed to be constant only for the duration of the replacer function
1436 * call and only if the replacer function does not modify this matcher's
1437 * state.
1438 *
1439 * @implNote
1440 * This implementation applies the replacer function to this matcher, which
1441 * is an instance of {@code MatchResult}.
1442 *
1443 * @param replacer
1444 * The function to be applied to the match result of this matcher
1445 * that returns a replacement string.
1446 * @return The string constructed by replacing the first matching
1447 * subsequence with the result of applying the replacer function to
1448 * the matched subsequence, substituting captured subsequences as
1449 * needed.
1450 * @throws NullPointerException if the replacer function is null
1451 * @throws ConcurrentModificationException if it is detected, on a
1452 * best-effort basis, that the replacer function modified this
1453 * matcher's state
1454 * @since 1.9
1455 */
1456 public String replaceFirst(Function<MatchResult, String> replacer) {
1457 Objects.requireNonNull(replacer);
1458 reset();
1459 if (!find())
1460 return text.toString();
1461 StringBuilder sb = new StringBuilder();
1462 int ec = modCount;
1463 String replacement = replacer.apply(this);
1464 if (ec != modCount)
1465 throw new ConcurrentModificationException();
1466 appendReplacement(sb, replacement);
1467 appendTail(sb);
1468 return sb.toString();
1469 }
1470
1471 /**
1472 * Sets the limits of this matcher's region. The region is the part of the
1473 * input sequence that will be searched to find a match. Invoking this
1474 * method resets the matcher, and then sets the region to start at the
|
957 * m.appendReplacement(sb, "dog");
958 * }
959 * m.appendTail(sb);
960 * System.out.println(sb.toString());</pre></blockquote>
961 *
962 * @param sb
963 * The target string builder
964 * @param replacement
965 * The replacement string
966 * @return This matcher
967 *
968 * @throws IllegalStateException
969 * If no match has yet been attempted,
970 * or if the previous match operation failed
971 * @throws IllegalArgumentException
972 * If the replacement string refers to a named-capturing
973 * group that does not exist in the pattern
974 * @throws IndexOutOfBoundsException
975 * If the replacement string refers to a capturing group
976 * that does not exist in the pattern
977 * @since 9
978 */
979 public Matcher appendReplacement(StringBuilder sb, String replacement) {
980 // If no match, return error
981 if (first < 0)
982 throw new IllegalStateException("No match available");
983 StringBuilder result = new StringBuilder();
984 appendExpandedReplacement(replacement, result);
985 // Append the intervening text
986 sb.append(text, lastAppendPosition, first);
987 // Append the match substitution
988 sb.append(result);
989 lastAppendPosition = last;
990 modCount++;
991 return this;
992 }
993
994 /**
995 * Processes replacement string to replace group references with
996 * groups.
997 */
1100 */
1101 public StringBuffer appendTail(StringBuffer sb) {
1102 sb.append(text, lastAppendPosition, getTextLength());
1103 return sb;
1104 }
1105
1106 /**
1107 * Implements a terminal append-and-replace step.
1108 *
1109 * <p> This method reads characters from the input sequence, starting at
1110 * the append position, and appends them to the given string builder. It is
1111 * intended to be invoked after one or more invocations of the {@link
1112 * #appendReplacement appendReplacement} method in order to copy the
1113 * remainder of the input sequence. </p>
1114 *
1115 * @param sb
1116 * The target string builder
1117 *
1118 * @return The target string builder
1119 *
1120 * @since 9
1121 */
1122 public StringBuilder appendTail(StringBuilder sb) {
1123 sb.append(text, lastAppendPosition, getTextLength());
1124 return sb;
1125 }
1126
1127 /**
1128 * Replaces every subsequence of the input sequence that matches the
1129 * pattern with the given replacement string.
1130 *
1131 * <p> This method first resets this matcher. It then scans the input
1132 * sequence looking for matches of the pattern. Characters that are not
1133 * part of any match are appended directly to the result string; each match
1134 * is replaced in the result by the replacement string. The replacement
1135 * string may contain references to captured subsequences as in the {@link
1136 * #appendReplacement appendReplacement} method.
1137 *
1138 * <p> Note that backslashes ({@code \}) and dollar signs ({@code $}) in
1139 * the replacement string may cause the results to be different than if it
1140 * were being treated as a literal replacement string. Dollar signs may be
1212 * <p> The state of each match result passed to the replacer function is
1213 * guaranteed to be constant only for the duration of the replacer function
1214 * call and only if the replacer function does not modify this matcher's
1215 * state.
1216 *
1217 * @implNote
1218 * This implementation applies the replacer function to this matcher, which
1219 * is an instance of {@code MatchResult}.
1220 *
1221 * @param replacer
1222 * The function to be applied to the match result of this matcher
1223 * that returns a replacement string.
1224 * @return The string constructed by replacing each matching subsequence
1225 * with the result of applying the replacer function to that
1226 * matched subsequence, substituting captured subsequences as
1227 * needed.
1228 * @throws NullPointerException if the replacer function is null
1229 * @throws ConcurrentModificationException if it is detected, on a
1230 * best-effort basis, that the replacer function modified this
1231 * matcher's state
1232 * @since 9
1233 */
1234 public String replaceAll(Function<MatchResult, String> replacer) {
1235 Objects.requireNonNull(replacer);
1236 reset();
1237 boolean result = find();
1238 if (result) {
1239 StringBuilder sb = new StringBuilder();
1240 do {
1241 int ec = modCount;
1242 String replacement = replacer.apply(this);
1243 if (ec != modCount)
1244 throw new ConcurrentModificationException();
1245 appendReplacement(sb, replacement);
1246 result = find();
1247 } while (result);
1248 appendTail(sb);
1249 return sb.toString();
1250 }
1251 return text.toString();
1252 }
1256 * sequence that matches the pattern. The match results occur in the
1257 * same order as the matching subsequences in the input sequence.
1258 *
1259 * <p> Each match result is produced as if by {@link #toMatchResult()}.
1260 *
1261 * <p> This method does not reset this matcher. Matching starts on
1262 * initiation of the terminal stream operation either at the beginning of
1263 * this matcher's region, or, if the matcher has not since been reset, at
1264 * the first character not matched by a previous match.
1265 *
1266 * <p> If the matcher is to be used for further matching operations after
1267 * the terminal stream operation completes then it should be first reset.
1268 *
1269 * <p> This matcher's state should not be modified during execution of the
1270 * returned stream's pipeline. The returned stream's source
1271 * {@code Spliterator} is <em>fail-fast</em> and will, on a best-effort
1272 * basis, throw a {@link java.util.ConcurrentModificationException} if such
1273 * modification is detected.
1274 *
1275 * @return a sequential stream of match results.
1276 * @since 9
1277 */
1278 public Stream<MatchResult> results() {
1279 class MatchResultIterator implements Iterator<MatchResult> {
1280 // -ve for call to find, 0 for not found, 1 for found
1281 int state = -1;
1282 // State for concurrent modification checking
1283 // -1 for uninitialized
1284 int expectedCount = -1;
1285 // The input sequence as a string, set once only after first find
1286 // Avoids repeated conversion from CharSequence for each match
1287 String textAsString;
1288
1289 @Override
1290 public MatchResult next() {
1291 if (expectedCount >= 0 && expectedCount != modCount)
1292 throw new ConcurrentModificationException();
1293
1294 if (!hasNext())
1295 throw new NoSuchElementException();
1296
1434 * <p> The state of the match result passed to the replacer function is
1435 * guaranteed to be constant only for the duration of the replacer function
1436 * call and only if the replacer function does not modify this matcher's
1437 * state.
1438 *
1439 * @implNote
1440 * This implementation applies the replacer function to this matcher, which
1441 * is an instance of {@code MatchResult}.
1442 *
1443 * @param replacer
1444 * The function to be applied to the match result of this matcher
1445 * that returns a replacement string.
1446 * @return The string constructed by replacing the first matching
1447 * subsequence with the result of applying the replacer function to
1448 * the matched subsequence, substituting captured subsequences as
1449 * needed.
1450 * @throws NullPointerException if the replacer function is null
1451 * @throws ConcurrentModificationException if it is detected, on a
1452 * best-effort basis, that the replacer function modified this
1453 * matcher's state
1454 * @since 9
1455 */
1456 public String replaceFirst(Function<MatchResult, String> replacer) {
1457 Objects.requireNonNull(replacer);
1458 reset();
1459 if (!find())
1460 return text.toString();
1461 StringBuilder sb = new StringBuilder();
1462 int ec = modCount;
1463 String replacement = replacer.apply(this);
1464 if (ec != modCount)
1465 throw new ConcurrentModificationException();
1466 appendReplacement(sb, replacement);
1467 appendTail(sb);
1468 return sb.toString();
1469 }
1470
1471 /**
1472 * Sets the limits of this matcher's region. The region is the part of the
1473 * input sequence that will be searched to find a match. Invoking this
1474 * method resets the matcher, and then sets the region to start at the
|