View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.lang3;
18  
19  import java.util.Objects;
20  import java.util.regex.Matcher;
21  import java.util.regex.Pattern;
22  
23  /**
24   * Helpers to process Strings using regular expressions.
25   *
26   * @see java.util.regex.Pattern
27   * @since 3.8
28   */
29  public class RegExUtils {
30  
31      /**
32       * The pattern to split version strings.
33       */
34      static final Pattern VERSION_SPLIT_PATTERN = Pattern.compile("\\.");
35  
36      /**
37       * Compiles the given regular expression into a pattern with the {@link Pattern#DOTALL} flag.
38       *
39       * @param regex The expression to be compiled.
40       * @return The given regular expression compiled into a pattern with the {@link Pattern#DOTALL} flag.
41       * @since 3.13.0
42       */
43      public static Pattern dotAll(final String regex) {
44          return Pattern.compile(regex, Pattern.DOTALL);
45      }
46  
47      /**
48       * Compiles the given regular expression into a pattern with the {@link Pattern#DOTALL} flag, then creates a matcher that will match the given text against
49       * this pattern.
50       *
51       * @param regex The expression to be compiled.
52       * @param text  The character sequence to be matched.
53       * @return A new matcher for this pattern.
54       * @since 3.18.0
55       */
56      public static Matcher dotAllMatcher(final String regex, final CharSequence text) {
57          return dotAll(regex).matcher(text);
58      }
59  
60      /**
61       * Compiles the given regular expression into a pattern with the {@link Pattern#DOTALL} flag, then creates a matcher that will match the given text against
62       * this pattern.
63       *
64       * @param regex The expression to be compiled.
65       * @param text  The character sequence to be matched.
66       * @return A new matcher for this pattern.
67       * @since 3.13.0
68       * @deprecated Use {@link #dotAllMatcher(String, CharSequence)}.
69       */
70      @Deprecated
71      public static Matcher dotAllMatcher(final String regex, final String text) {
72          return dotAll(regex).matcher(text);
73      }
74  
75      /**
76       * Removes each substring of the text String that matches the given regular expression pattern.
77       *
78       * This method is a {@code null} safe equivalent to:
79       * <ul>
80       *  <li>{@code pattern.matcher(text).replaceAll(StringUtils.EMPTY)}</li>
81       * </ul>
82       *
83       * <p>
84       * A {@code null} reference passed to this method is a no-op.
85       * </p>
86       *
87       * <pre>{@code
88       * RegExUtils.removeAll(null, *)      = null
89       * RegExUtils.removeAll("any", (Pattern) null)  = "any"
90       * RegExUtils.removeAll("any", Pattern.compile(""))    = "any"
91       * RegExUtils.removeAll("any", Pattern.compile(".*"))  = ""
92       * RegExUtils.removeAll("any", Pattern.compile(".+"))  = ""
93       * RegExUtils.removeAll("abc", Pattern.compile(".?"))  = ""
94       * RegExUtils.removeAll("A<__>\n<__>B", Pattern.compile("<.*>"))      = "A\nB"
95       * RegExUtils.removeAll("A<__>\n<__>B", Pattern.compile("(?s)<.*>"))  = "AB"
96       * RegExUtils.removeAll("A<__>\n<__>B", Pattern.compile("<.*>", Pattern.DOTALL))  = "AB"
97       * RegExUtils.removeAll("ABCabc123abc", Pattern.compile("[a-z]"))     = "ABC123"
98       * }</pre>
99       *
100      * @param text  text to remove from, may be null.
101      * @param regex  The regular expression to which this string is to be matched.
102      * @return  the text with any removes processed,
103      *              {@code null} if null String input.
104      *
105      * @see #replaceAll(CharSequence, Pattern, String)
106      * @see java.util.regex.Matcher#replaceAll(String)
107      * @see java.util.regex.Pattern
108      * @since 3.18.0
109      */
110     public static String removeAll(final CharSequence text, final Pattern regex) {
111         return replaceAll(text, regex, StringUtils.EMPTY);
112     }
113 
114     /**
115      * Removes each substring of the text String that matches the given regular expression pattern.
116      *
117      * This method is a {@code null} safe equivalent to:
118      * <ul>
119      *  <li>{@code pattern.matcher(text).replaceAll(StringUtils.EMPTY)}</li>
120      * </ul>
121      *
122      * <p>
123      * A {@code null} reference passed to this method is a no-op.
124      * </p>
125      *
126      * <pre>{@code
127      * RegExUtils.removeAll(null, *)      = null
128      * RegExUtils.removeAll("any", (Pattern) null)  = "any"
129      * RegExUtils.removeAll("any", Pattern.compile(""))    = "any"
130      * RegExUtils.removeAll("any", Pattern.compile(".*"))  = ""
131      * RegExUtils.removeAll("any", Pattern.compile(".+"))  = ""
132      * RegExUtils.removeAll("abc", Pattern.compile(".?"))  = ""
133      * RegExUtils.removeAll("A<__>\n<__>B", Pattern.compile("<.*>"))      = "A\nB"
134      * RegExUtils.removeAll("A<__>\n<__>B", Pattern.compile("(?s)<.*>"))  = "AB"
135      * RegExUtils.removeAll("A<__>\n<__>B", Pattern.compile("<.*>", Pattern.DOTALL))  = "AB"
136      * RegExUtils.removeAll("ABCabc123abc", Pattern.compile("[a-z]"))     = "ABC123"
137      * }</pre>
138      *
139      * @param text  text to remove from, may be null.
140      * @param regex  The regular expression to which this string is to be matched
141      * @return  the text with any removes processed,
142      *              {@code null} if null String input.
143      *
144      * @see #replaceAll(CharSequence, Pattern, String)
145      * @see java.util.regex.Matcher#replaceAll(String)
146      * @see java.util.regex.Pattern
147      * @deprecated Use {@link #removeAll(CharSequence, Pattern)}.
148      */
149     @Deprecated
150     public static String removeAll(final String text, final Pattern regex) {
151         return replaceAll((CharSequence) text, regex, StringUtils.EMPTY);
152     }
153 
154     /**
155      * Removes each substring of the text String that matches the given regular expression.
156      *
157      * This method is a {@code null} safe equivalent to:
158      * <ul>
159      *  <li>{@code text.replaceAll(regex, StringUtils.EMPTY)}</li>
160      *  <li>{@code Pattern.compile(regex).matcher(text).replaceAll(StringUtils.EMPTY)}</li>
161      * </ul>
162      *
163      * <p>
164      * A {@code null} reference passed to this method is a no-op.
165      * </p>
166      *
167      * <p>
168      * Unlike in the {@link #removePattern(CharSequence, String)} method, the {@link Pattern#DOTALL} option
169      * is NOT automatically added.
170      * To use the DOTALL option prepend {@code "(?s)"} to the regex.
171      * DOTALL is also known as single-line mode in Perl.
172      * </p>
173      *
174      * <pre>{@code
175      * RegExUtils.removeAll(null, *)      = null
176      * RegExUtils.removeAll("any", (String) null)  = "any"
177      * RegExUtils.removeAll("any", "")    = "any"
178      * RegExUtils.removeAll("any", ".*")  = ""
179      * RegExUtils.removeAll("any", ".+")  = ""
180      * RegExUtils.removeAll("abc", ".?")  = ""
181      * RegExUtils.removeAll("A<__>\n<__>B", "<.*>")      = "A\nB"
182      * RegExUtils.removeAll("A<__>\n<__>B", "(?s)<.*>")  = "AB"
183      * RegExUtils.removeAll("ABCabc123abc", "[a-z]")     = "ABC123"
184      * }</pre>
185      *
186      * @param text  text to remove from, may be null
187      * @param regex  The regular expression to which this string is to be matched
188      * @return  the text with any removes processed,
189      *              {@code null} if null String input.
190      *
191      * @throws  java.util.regex.PatternSyntaxException
192      *              Thrown if the regular expression's syntax is invalid.
193      *
194      * @see #replaceAll(String, String, String)
195      * @see #removePattern(CharSequence, String)
196      * @see String#replaceAll(String, String)
197      * @see java.util.regex.Pattern
198      * @see java.util.regex.Pattern#DOTALL
199      */
200     public static String removeAll(final String text, final String regex) {
201         return replaceAll(text, regex, StringUtils.EMPTY);
202     }
203 
204     /**
205      * Removes the first substring of the text string that matches the given regular expression pattern.
206      *
207      * This method is a {@code null} safe equivalent to:
208      * <ul>
209      *  <li>{@code pattern.matcher(text).replaceFirst(StringUtils.EMPTY)}</li>
210      * </ul>
211      *
212      * <p>
213      * A {@code null} reference passed to this method is a no-op.
214      * </p>
215      *
216      * <pre>{@code
217      * RegExUtils.removeFirst(null, *)      = null
218      * RegExUtils.removeFirst("any", (Pattern) null)  = "any"
219      * RegExUtils.removeFirst("any", Pattern.compile(""))    = "any"
220      * RegExUtils.removeFirst("any", Pattern.compile(".*"))  = ""
221      * RegExUtils.removeFirst("any", Pattern.compile(".+"))  = ""
222      * RegExUtils.removeFirst("abc", Pattern.compile(".?"))  = "bc"
223      * RegExUtils.removeFirst("A<__>\n<__>B", Pattern.compile("<.*>"))      = "A\n<__>B"
224      * RegExUtils.removeFirst("A<__>\n<__>B", Pattern.compile("(?s)<.*>"))  = "AB"
225      * RegExUtils.removeFirst("ABCabc123", Pattern.compile("[a-z]"))          = "ABCbc123"
226      * RegExUtils.removeFirst("ABCabc123abc", Pattern.compile("[a-z]+"))      = "ABC123abc"
227      * }</pre>
228      *
229      * @param text  text to remove from, may be null.
230      * @param regex  The regular expression pattern to which this string is to be matched.
231      * @return  the text with the first replacement processed,
232      *              {@code null} if null String input.
233      *
234      * @see #replaceFirst(String, Pattern, String)
235      * @see java.util.regex.Matcher#replaceFirst(String)
236      * @see java.util.regex.Pattern
237      * @since 3.18.0
238      */
239     public static String removeFirst(final CharSequence text, final Pattern regex) {
240         return replaceFirst(text, regex, StringUtils.EMPTY);
241     }
242 
243     /**
244      * Removes the first substring of the text string that matches the given regular expression pattern.
245      *
246      * This method is a {@code null} safe equivalent to:
247      * <ul>
248      *  <li>{@code pattern.matcher(text).replaceFirst(StringUtils.EMPTY)}</li>
249      * </ul>
250      *
251      * <p>
252      * A {@code null} reference passed to this method is a no-op.
253      * </p>
254      *
255      * <pre>{@code
256      * RegExUtils.removeFirst(null, *)      = null
257      * RegExUtils.removeFirst("any", (Pattern) null)  = "any"
258      * RegExUtils.removeFirst("any", Pattern.compile(""))    = "any"
259      * RegExUtils.removeFirst("any", Pattern.compile(".*"))  = ""
260      * RegExUtils.removeFirst("any", Pattern.compile(".+"))  = ""
261      * RegExUtils.removeFirst("abc", Pattern.compile(".?"))  = "bc"
262      * RegExUtils.removeFirst("A<__>\n<__>B", Pattern.compile("<.*>"))      = "A\n<__>B"
263      * RegExUtils.removeFirst("A<__>\n<__>B", Pattern.compile("(?s)<.*>"))  = "AB"
264      * RegExUtils.removeFirst("ABCabc123", Pattern.compile("[a-z]"))          = "ABCbc123"
265      * RegExUtils.removeFirst("ABCabc123abc", Pattern.compile("[a-z]+"))      = "ABC123abc"
266      * }</pre>
267      *
268      * @param text  text to remove from, may be null.
269      * @param regex  The regular expression pattern to which this string is to be matched.
270      * @return  the text with the first replacement processed,
271      *              {@code null} if null String input.
272      *
273      * @see #replaceFirst(String, Pattern, String)
274      * @see java.util.regex.Matcher#replaceFirst(String)
275      * @see java.util.regex.Pattern
276      * @deprecated Use {@link #removeFirst(CharSequence, Pattern)}.
277      */
278     @Deprecated
279     public static String removeFirst(final String text, final Pattern regex) {
280         return replaceFirst(text, regex, StringUtils.EMPTY);
281     }
282 
283     /**
284      * Removes the first substring of the text string that matches the given regular expression.
285      *
286      * This method is a {@code null} safe equivalent to:
287      * <ul>
288      *  <li>{@code text.replaceFirst(regex, StringUtils.EMPTY)}</li>
289      *  <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(StringUtils.EMPTY)}</li>
290      * </ul>
291      *
292      * <p>
293      * A {@code null} reference passed to this method is a no-op.
294      * </p>
295      *
296      * <p>
297      * The {@link Pattern#DOTALL} option is NOT automatically added.
298      * To use the DOTALL option prepend {@code "(?s)"} to the regex.
299      * DOTALL is also known as single-line mode in Perl.
300      * </p>
301      *
302      * <pre>{@code
303      * RegExUtils.removeFirst(null, *)      = null
304      * RegExUtils.removeFirst("any", (String) null)  = "any"
305      * RegExUtils.removeFirst("any", "")    = "any"
306      * RegExUtils.removeFirst("any", ".*")  = ""
307      * RegExUtils.removeFirst("any", ".+")  = ""
308      * RegExUtils.removeFirst("abc", ".?")  = "bc"
309      * RegExUtils.removeFirst("A<__>\n<__>B", "<.*>")      = "A\n<__>B"
310      * RegExUtils.removeFirst("A<__>\n<__>B", "(?s)<.*>")  = "AB"
311      * RegExUtils.removeFirst("ABCabc123", "[a-z]")          = "ABCbc123"
312      * RegExUtils.removeFirst("ABCabc123abc", "[a-z]+")      = "ABC123abc"
313      * }</pre>
314      *
315      * @param text  text to remove from, may be null.
316      * @param regex  The regular expression to which this string is to be matched.
317      * @return  the text with the first replacement processed,
318      *              {@code null} if null String input.
319      *
320      * @throws  java.util.regex.PatternSyntaxException
321      *              Thrown if the regular expression's syntax is invalid.
322      *
323      * @see #replaceFirst(String, String, String)
324      * @see String#replaceFirst(String, String)
325      * @see java.util.regex.Pattern
326      * @see java.util.regex.Pattern#DOTALL
327      */
328     public static String removeFirst(final String text, final String regex) {
329         return replaceFirst(text, regex, StringUtils.EMPTY);
330     }
331 
332     /**
333      * Removes each substring of the source String that matches the given regular expression using the DOTALL option.
334      *
335      * This call is a {@code null} safe equivalent to:
336      * <ul>
337      * <li>{@code text.replaceAll(&quot;(?s)&quot; + regex, StringUtils.EMPTY)}</li>
338      * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(text).replaceAll(StringUtils.EMPTY)}</li>
339      * </ul>
340      *
341      * <p>
342      * A {@code null} reference passed to this method is a no-op.
343      * </p>
344      *
345      * <pre>{@code
346      * RegExUtils.removePattern(null, *)       = null
347      * RegExUtils.removePattern("any", (String) null)   = "any"
348      * RegExUtils.removePattern("A<__>\n<__>B", "<.*>")  = "AB"
349      * RegExUtils.removePattern("ABCabc123", "[a-z]")    = "ABC123"
350      * }</pre>
351      *
352      * @param text
353      *            the source string.
354      * @param regex
355      *            the regular expression to which this string is to be matched.
356      * @return The resulting {@link String}.
357      * @see #replacePattern(CharSequence, String, String)
358      * @see String#replaceAll(String, String)
359      * @see Pattern#DOTALL
360      * @since 3.18.0
361      */
362     public static String removePattern(final CharSequence text, final String regex) {
363         return replacePattern(text, regex, StringUtils.EMPTY);
364     }
365 
366     /**
367      * Removes each substring of the source String that matches the given regular expression using the DOTALL option.
368      *
369      * This call is a {@code null} safe equivalent to:
370      * <ul>
371      * <li>{@code text.replaceAll(&quot;(?s)&quot; + regex, StringUtils.EMPTY)}</li>
372      * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(text).replaceAll(StringUtils.EMPTY)}</li>
373      * </ul>
374      *
375      * <p>
376      * A {@code null} reference passed to this method is a no-op.
377      * </p>
378      *
379      * <pre>{@code
380      * RegExUtils.removePattern(null, *)       = null
381      * RegExUtils.removePattern("any", (String) null)   = "any"
382      * RegExUtils.removePattern("A<__>\n<__>B", "<.*>")  = "AB"
383      * RegExUtils.removePattern("ABCabc123", "[a-z]")    = "ABC123"
384      * }</pre>
385      *
386      * @param text
387      *            the source string.
388      * @param regex
389      *            the regular expression to which this string is to be matched.
390      * @return The resulting {@link String}.
391      * @see #replacePattern(CharSequence, String, String)
392      * @see String#replaceAll(String, String)
393      * @see Pattern#DOTALL
394      * @deprecated Use {@link #removePattern(CharSequence, String)}.
395      */
396     @Deprecated
397     public static String removePattern(final String text, final String regex) {
398         return replacePattern((CharSequence) text, regex, StringUtils.EMPTY);
399     }
400 
401     /**
402      * Replaces each substring of the text String that matches the given regular expression pattern with the given replacement.
403      *
404      * This method is a {@code null} safe equivalent to:
405      * <ul>
406      *  <li>{@code pattern.matcher(text).replaceAll(replacement)}</li>
407      * </ul>
408      *
409      * <p>
410      * A {@code null} reference passed to this method is a no-op.
411      * </p>
412      *
413      * <pre>{@code
414      * RegExUtils.replaceAll(null, *, *)       = null
415      * RegExUtils.replaceAll("any", (Pattern) null, *)   = "any"
416      * RegExUtils.replaceAll("any", *, null)   = "any"
417      * RegExUtils.replaceAll("", Pattern.compile(""), "zzz")    = "zzz"
418      * RegExUtils.replaceAll("", Pattern.compile(".*"), "zzz")  = "zzz"
419      * RegExUtils.replaceAll("", Pattern.compile(".+"), "zzz")  = ""
420      * RegExUtils.replaceAll("abc", Pattern.compile(""), "ZZ")  = "ZZaZZbZZcZZ"
421      * RegExUtils.replaceAll("<__>\n<__>", Pattern.compile("<.*>"), "z")                 = "z\nz"
422      * RegExUtils.replaceAll("<__>\n<__>", Pattern.compile("<.*>", Pattern.DOTALL), "z") = "z"
423      * RegExUtils.replaceAll("<__>\n<__>", Pattern.compile("(?s)<.*>"), "z")             = "z"
424      * RegExUtils.replaceAll("ABCabc123", Pattern.compile("[a-z]"), "_")       = "ABC___123"
425      * RegExUtils.replaceAll("ABCabc123", Pattern.compile("[^A-Z0-9]+"), "_")  = "ABC_123"
426      * RegExUtils.replaceAll("ABCabc123", Pattern.compile("[^A-Z0-9]+"), "")   = "ABC123"
427      * RegExUtils.replaceAll("Lorem ipsum  dolor   sit", Pattern.compile("( +)([a-z]+)"), "_$2")  = "Lorem_ipsum_dolor_sit"
428      * }</pre>
429      *
430      * @param text  text to search and replace in, may be null.
431      * @param regex  The regular expression pattern to which this string is to be matched.
432      * @param replacement  The string to be substituted for each match.
433      * @return  the text with any replacements processed,
434      *              {@code null} if null String input.
435      * @see java.util.regex.Matcher#replaceAll(String)
436      * @see java.util.regex.Pattern
437      */
438     public static String replaceAll(final CharSequence text, final Pattern regex, final String replacement) {
439         if (ObjectUtils.anyNull(text, regex, replacement)) {
440             return toStringOrNull(text);
441         }
442         return regex.matcher(text).replaceAll(replacement);
443     }
444 
445     /**
446      * Replaces each substring of the text String that matches the given regular expression pattern with the given replacement.
447      *
448      * This method is a {@code null} safe equivalent to:
449      * <ul>
450      *  <li>{@code pattern.matcher(text).replaceAll(replacement)}</li>
451      * </ul>
452      *
453      * <p>
454      * A {@code null} reference passed to this method is a no-op.
455      * </p>
456      *
457      * <pre>{@code
458      * RegExUtils.replaceAll(null, *, *)       = null
459      * RegExUtils.replaceAll("any", (Pattern) null, *)   = "any"
460      * RegExUtils.replaceAll("any", *, null)   = "any"
461      * RegExUtils.replaceAll("", Pattern.compile(""), "zzz")    = "zzz"
462      * RegExUtils.replaceAll("", Pattern.compile(".*"), "zzz")  = "zzz"
463      * RegExUtils.replaceAll("", Pattern.compile(".+"), "zzz")  = ""
464      * RegExUtils.replaceAll("abc", Pattern.compile(""), "ZZ")  = "ZZaZZbZZcZZ"
465      * RegExUtils.replaceAll("<__>\n<__>", Pattern.compile("<.*>"), "z")                 = "z\nz"
466      * RegExUtils.replaceAll("<__>\n<__>", Pattern.compile("<.*>", Pattern.DOTALL), "z") = "z"
467      * RegExUtils.replaceAll("<__>\n<__>", Pattern.compile("(?s)<.*>"), "z")             = "z"
468      * RegExUtils.replaceAll("ABCabc123", Pattern.compile("[a-z]"), "_")       = "ABC___123"
469      * RegExUtils.replaceAll("ABCabc123", Pattern.compile("[^A-Z0-9]+"), "_")  = "ABC_123"
470      * RegExUtils.replaceAll("ABCabc123", Pattern.compile("[^A-Z0-9]+"), "")   = "ABC123"
471      * RegExUtils.replaceAll("Lorem ipsum  dolor   sit", Pattern.compile("( +)([a-z]+)"), "_$2")  = "Lorem_ipsum_dolor_sit"
472      * }</pre>
473      *
474      * @param text  text to search and replace in, may be null.
475      * @param regex  The regular expression pattern to which this string is to be matched.
476      * @param replacement  The string to be substituted for each match.
477      * @return  the text with any replacements processed,
478      *              {@code null} if null String input.
479      * @see java.util.regex.Matcher#replaceAll(String)
480      * @see java.util.regex.Pattern
481      * @deprecated Use {@link #replaceAll(CharSequence, Pattern, String)}.
482      */
483     @Deprecated
484     public static String replaceAll(final String text, final Pattern regex, final String replacement) {
485         return replaceAll((CharSequence) text, regex, replacement);
486     }
487 
488     /**
489      * Replaces each substring of the text String that matches the given regular expression
490      * with the given replacement.
491      *
492      * This method is a {@code null} safe equivalent to:
493      * <ul>
494      *  <li>{@code text.replaceAll(regex, replacement)}</li>
495      *  <li>{@code Pattern.compile(regex).matcher(text).replaceAll(replacement)}</li>
496      * </ul>
497      *
498      * <p>
499      * A {@code null} reference passed to this method is a no-op.
500      * </p>
501      *
502      * <p>
503      * Unlike in the {@link #replacePattern(CharSequence, String, String)} method, the {@link Pattern#DOTALL} option
504      * is NOT automatically added.
505      * To use the DOTALL option prepend {@code "(?s)"} to the regex.
506      * DOTALL is also known as single-line mode in Perl.
507      * </p>
508      *
509      * <pre>{@code
510      * RegExUtils.replaceAll(null, *, *)       = null
511      * RegExUtils.replaceAll("any", (String) null, *)   = "any"
512      * RegExUtils.replaceAll("any", *, null)   = "any"
513      * RegExUtils.replaceAll("", "", "zzz")    = "zzz"
514      * RegExUtils.replaceAll("", ".*", "zzz")  = "zzz"
515      * RegExUtils.replaceAll("", ".+", "zzz")  = ""
516      * RegExUtils.replaceAll("abc", "", "ZZ")  = "ZZaZZbZZcZZ"
517      * RegExUtils.replaceAll("<__>\n<__>", "<.*>", "z")      = "z\nz"
518      * RegExUtils.replaceAll("<__>\n<__>", "(?s)<.*>", "z")  = "z"
519      * RegExUtils.replaceAll("ABCabc123", "[a-z]", "_")       = "ABC___123"
520      * RegExUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "_")  = "ABC_123"
521      * RegExUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "")   = "ABC123"
522      * RegExUtils.replaceAll("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
523      * }</pre>
524      *
525      * @param text  text to search and replace in, may be null.
526      * @param regex  The regular expression to which this string is to be matched.
527      * @param replacement  The string to be substituted for each match.
528      * @return  the text with any replacements processed,
529      *              {@code null} if null String input.
530      * @throws  java.util.regex.PatternSyntaxException
531      *              Thrown if the regular expression's syntax is invalid.
532      * @see #replacePattern(String, String, String)
533      * @see String#replaceAll(String, String)
534      * @see java.util.regex.Pattern
535      * @see java.util.regex.Pattern#DOTALL
536      */
537     public static String replaceAll(final String text, final String regex, final String replacement) {
538         if (ObjectUtils.anyNull(text, regex, replacement)) {
539             return text;
540         }
541         return text.replaceAll(regex, replacement);
542     }
543 
544     /**
545      * Replaces the first substring of the text string that matches the given regular expression pattern
546      * with the given replacement.
547      *
548      * This method is a {@code null} safe equivalent to:
549      * <ul>
550      *  <li>{@code pattern.matcher(text).replaceFirst(replacement)}</li>
551      * </ul>
552      *
553      * <p>
554      * A {@code null} reference passed to this method is a no-op.
555      * </p>
556      *
557      * <pre>{@code
558      * RegExUtils.replaceFirst(null, *, *)       = null
559      * RegExUtils.replaceFirst("any", (Pattern) null, *)   = "any"
560      * RegExUtils.replaceFirst("any", *, null)   = "any"
561      * RegExUtils.replaceFirst("", Pattern.compile(""), "zzz")    = "zzz"
562      * RegExUtils.replaceFirst("", Pattern.compile(".*"), "zzz")  = "zzz"
563      * RegExUtils.replaceFirst("", Pattern.compile(".+"), "zzz")  = ""
564      * RegExUtils.replaceFirst("abc", Pattern.compile(""), "ZZ")  = "ZZabc"
565      * RegExUtils.replaceFirst("<__>\n<__>", Pattern.compile("<.*>"), "z")      = "z\n<__>"
566      * RegExUtils.replaceFirst("<__>\n<__>", Pattern.compile("(?s)<.*>"), "z")  = "z"
567      * RegExUtils.replaceFirst("ABCabc123", Pattern.compile("[a-z]"), "_")          = "ABC_bc123"
568      * RegExUtils.replaceFirst("ABCabc123abc", Pattern.compile("[^A-Z0-9]+"), "_")  = "ABC_123abc"
569      * RegExUtils.replaceFirst("ABCabc123abc", Pattern.compile("[^A-Z0-9]+"), "")   = "ABC123abc"
570      * RegExUtils.replaceFirst("Lorem ipsum  dolor   sit", Pattern.compile("( +)([a-z]+)"), "_$2")  = "Lorem_ipsum  dolor   sit"
571      * }</pre>
572      *
573      * @param text  text to search and replace in, may be null.
574      * @param regex  The regular expression pattern to which this string is to be matched.
575      * @param replacement  The string to be substituted for the first match
576      * @return  the text with the first replacement processed,
577      *              {@code null} if null String input.
578      * @see java.util.regex.Matcher#replaceFirst(String)
579      * @see java.util.regex.Pattern
580      * @since 3.18.0
581      */
582     public static String replaceFirst(final CharSequence text, final Pattern regex, final String replacement) {
583         if (text == null || regex == null || replacement == null) {
584             return toStringOrNull(text);
585         }
586         return regex.matcher(text).replaceFirst(replacement);
587     }
588 
589     /**
590      * Replaces the first substring of the text string that matches the given regular expression pattern
591      * with the given replacement.
592      *
593      * This method is a {@code null} safe equivalent to:
594      * <ul>
595      *  <li>{@code pattern.matcher(text).replaceFirst(replacement)}</li>
596      * </ul>
597      *
598      * <p>
599      * A {@code null} reference passed to this method is a no-op.
600      * </p>
601      *
602      * <pre>{@code
603      * RegExUtils.replaceFirst(null, *, *)       = null
604      * RegExUtils.replaceFirst("any", (Pattern) null, *)   = "any"
605      * RegExUtils.replaceFirst("any", *, null)   = "any"
606      * RegExUtils.replaceFirst("", Pattern.compile(""), "zzz")    = "zzz"
607      * RegExUtils.replaceFirst("", Pattern.compile(".*"), "zzz")  = "zzz"
608      * RegExUtils.replaceFirst("", Pattern.compile(".+"), "zzz")  = ""
609      * RegExUtils.replaceFirst("abc", Pattern.compile(""), "ZZ")  = "ZZabc"
610      * RegExUtils.replaceFirst("<__>\n<__>", Pattern.compile("<.*>"), "z")      = "z\n<__>"
611      * RegExUtils.replaceFirst("<__>\n<__>", Pattern.compile("(?s)<.*>"), "z")  = "z"
612      * RegExUtils.replaceFirst("ABCabc123", Pattern.compile("[a-z]"), "_")          = "ABC_bc123"
613      * RegExUtils.replaceFirst("ABCabc123abc", Pattern.compile("[^A-Z0-9]+"), "_")  = "ABC_123abc"
614      * RegExUtils.replaceFirst("ABCabc123abc", Pattern.compile("[^A-Z0-9]+"), "")   = "ABC123abc"
615      * RegExUtils.replaceFirst("Lorem ipsum  dolor   sit", Pattern.compile("( +)([a-z]+)"), "_$2")  = "Lorem_ipsum  dolor   sit"
616      * }</pre>
617      *
618      * @param text  text to search and replace in, may be null.
619      * @param regex  The regular expression pattern to which this string is to be matched.
620      * @param replacement  The string to be substituted for the first match.
621      * @return  the text with the first replacement processed,
622      *              {@code null} if null String input.
623      * @see java.util.regex.Matcher#replaceFirst(String)
624      * @see java.util.regex.Pattern
625      * @deprecated Use {@link #replaceFirst(CharSequence, Pattern, String)}.
626      */
627     @Deprecated
628     public static String replaceFirst(final String text, final Pattern regex, final String replacement) {
629         return replaceFirst((CharSequence) text, regex, replacement);
630     }
631 
632     /**
633      * Replaces the first substring of the text string that matches the given regular expression
634      * with the given replacement.
635      *
636      * This method is a {@code null} safe equivalent to:
637      * <ul>
638      *  <li>{@code text.replaceFirst(regex, replacement)}</li>
639      *  <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(replacement)}</li>
640      * </ul>
641      *
642      * <p>
643      * A {@code null} reference passed to this method is a no-op.
644      * </p>
645      *
646      * <p>
647      * The {@link Pattern#DOTALL} option is NOT automatically added.
648      * To use the DOTALL option prepend {@code "(?s)"} to the regex.
649      * DOTALL is also known as single-line mode in Perl.
650      * </p>
651      *
652      * <pre>{@code
653      * RegExUtils.replaceFirst(null, *, *)       = null
654      * RegExUtils.replaceFirst("any", (String) null, *)   = "any"
655      * RegExUtils.replaceFirst("any", *, null)   = "any"
656      * RegExUtils.replaceFirst("", "", "zzz")    = "zzz"
657      * RegExUtils.replaceFirst("", ".*", "zzz")  = "zzz"
658      * RegExUtils.replaceFirst("", ".+", "zzz")  = ""
659      * RegExUtils.replaceFirst("abc", "", "ZZ")  = "ZZabc"
660      * RegExUtils.replaceFirst("<__>\n<__>", "<.*>", "z")      = "z\n<__>"
661      * RegExUtils.replaceFirst("<__>\n<__>", "(?s)<.*>", "z")  = "z"
662      * RegExUtils.replaceFirst("ABCabc123", "[a-z]", "_")          = "ABC_bc123"
663      * RegExUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "_")  = "ABC_123abc"
664      * RegExUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "")   = "ABC123abc"
665      * RegExUtils.replaceFirst("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum  dolor   sit"
666      * }</pre>
667      *
668      * @param text  text to search and replace in, may be null.
669      * @param regex  The regular expression to which this string is to be matched.
670      * @param replacement  The string to be substituted for the first match.
671      * @return  the text with the first replacement processed,
672      *              {@code null} if null String input.
673      * @throws  java.util.regex.PatternSyntaxException
674      *              Thrown if the regular expression's syntax is invalid.
675      * @see String#replaceFirst(String, String)
676      * @see java.util.regex.Pattern
677      * @see java.util.regex.Pattern#DOTALL
678      */
679     public static String replaceFirst(final String text, final String regex, final String replacement) {
680         if (text == null || regex == null || replacement == null) {
681             return text;
682         }
683         return text.replaceFirst(regex, replacement);
684     }
685 
686     /**
687      * Replaces each substring of the source String that matches the given regular expression with the given
688      * replacement using the {@link Pattern#DOTALL} option. DOTALL is also known as single-line mode in Perl.
689      *
690      * This call is a {@code null} safe equivalent to:
691      * <ul>
692      * <li>{@code text.replaceAll(&quot;(?s)&quot; + regex, replacement)}</li>
693      * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(text).replaceAll(replacement)}</li>
694      * </ul>
695      *
696      * <p>
697      * A {@code null} reference passed to this method is a no-op.
698      * </p>
699      *
700      * <pre>{@code
701      * RegExUtils.replacePattern(null, *, *)       = null
702      * RegExUtils.replacePattern("any", (String) null, *)   = "any"
703      * RegExUtils.replacePattern("any", *, null)   = "any"
704      * RegExUtils.replacePattern("", "", "zzz")    = "zzz"
705      * RegExUtils.replacePattern("", ".*", "zzz")  = "zzz"
706      * RegExUtils.replacePattern("", ".+", "zzz")  = ""
707      * RegExUtils.replacePattern("<__>\n<__>", "<.*>", "z")       = "z"
708      * RegExUtils.replacePattern("ABCabc123", "[a-z]", "_")       = "ABC___123"
709      * RegExUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "_")  = "ABC_123"
710      * RegExUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "")   = "ABC123"
711      * RegExUtils.replacePattern("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
712      * }</pre>
713      *
714      * @param text
715      *            the source string.
716      * @param regex
717      *            the regular expression to which this string is to be matched.
718      * @param replacement
719      *            the string to be substituted for each match.
720      * @return The resulting {@link String}.
721      * @see #replaceAll(String, String, String)
722      * @see String#replaceAll(String, String)
723      * @see Pattern#DOTALL
724      * @since 3.18.0
725      */
726     public static String replacePattern(final CharSequence text, final String regex, final String replacement) {
727         if (ObjectUtils.anyNull(text, regex, replacement)) {
728             return toStringOrNull(text);
729         }
730         return dotAllMatcher(regex, text).replaceAll(replacement);
731     }
732 
733     /**
734      * Replaces each substring of the source String that matches the given regular expression with the given
735      * replacement using the {@link Pattern#DOTALL} option. DOTALL is also known as single-line mode in Perl.
736      *
737      * This call is a {@code null} safe equivalent to:
738      * <ul>
739      * <li>{@code text.replaceAll(&quot;(?s)&quot; + regex, replacement)}</li>
740      * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(text).replaceAll(replacement)}</li>
741      * </ul>
742      *
743      * <p>
744      * A {@code null} reference passed to this method is a no-op.
745      * </p>
746      *
747      * <pre>{@code
748      * RegExUtils.replacePattern(null, *, *)       = null
749      * RegExUtils.replacePattern("any", (String) null, *)   = "any"
750      * RegExUtils.replacePattern("any", *, null)   = "any"
751      * RegExUtils.replacePattern("", "", "zzz")    = "zzz"
752      * RegExUtils.replacePattern("", ".*", "zzz")  = "zzz"
753      * RegExUtils.replacePattern("", ".+", "zzz")  = ""
754      * RegExUtils.replacePattern("<__>\n<__>", "<.*>", "z")       = "z"
755      * RegExUtils.replacePattern("ABCabc123", "[a-z]", "_")       = "ABC___123"
756      * RegExUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "_")  = "ABC_123"
757      * RegExUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "")   = "ABC123"
758      * RegExUtils.replacePattern("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
759      * }</pre>
760      *
761      * @param text
762      *            the source string.
763      * @param regex
764      *            the regular expression to which this string is to be matched.
765      * @param replacement
766      *            the string to be substituted for each match.
767      * @return The resulting {@link String}.
768      * @see #replaceAll(String, String, String)
769      * @see String#replaceAll(String, String)
770      * @see Pattern#DOTALL
771      * @deprecated Use {@link #replacePattern(CharSequence, String, String)}.
772      */
773     @Deprecated
774     public static String replacePattern(final String text, final String regex, final String replacement) {
775         return replacePattern((CharSequence) text, regex, replacement);
776     }
777 
778     private static String toStringOrNull(final CharSequence text) {
779         return Objects.toString(text, null);
780     }
781 
782     /**
783      * Make private in 4.0.
784      *
785      * @deprecated TODO Make private in 4.0.
786      */
787     @Deprecated
788     public RegExUtils() {
789         // empty
790     }
791 }