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>A {@code null} reference passed to this method is a no-op.</p>
84       *
85       * <pre>{@code
86       * StringUtils.removeAll(null, *)      = null
87       * StringUtils.removeAll("any", (Pattern) null)  = "any"
88       * StringUtils.removeAll("any", Pattern.compile(""))    = "any"
89       * StringUtils.removeAll("any", Pattern.compile(".*"))  = ""
90       * StringUtils.removeAll("any", Pattern.compile(".+"))  = ""
91       * StringUtils.removeAll("abc", Pattern.compile(".?"))  = ""
92       * StringUtils.removeAll("A<__>\n<__>B", Pattern.compile("<.*>"))      = "A\nB"
93       * StringUtils.removeAll("A<__>\n<__>B", Pattern.compile("(?s)<.*>"))  = "AB"
94       * StringUtils.removeAll("A<__>\n<__>B", Pattern.compile("<.*>", Pattern.DOTALL))  = "AB"
95       * StringUtils.removeAll("ABCabc123abc", Pattern.compile("[a-z]"))     = "ABC123"
96       * }</pre>
97       *
98       * @param text  text to remove from, may be null.
99       * @param regex  the regular expression to which this string is to be matched.
100      * @return  the text with any removes processed,
101      *              {@code null} if null String input.
102      *
103      * @see #replaceAll(CharSequence, Pattern, String)
104      * @see java.util.regex.Matcher#replaceAll(String)
105      * @see java.util.regex.Pattern
106      * @since 3.18.0
107      */
108     public static String removeAll(final CharSequence text, final Pattern regex) {
109         return replaceAll(text, regex, StringUtils.EMPTY);
110     }
111 
112     /**
113      * Removes each substring of the text String that matches the given regular expression pattern.
114      *
115      * This method is a {@code null} safe equivalent to:
116      * <ul>
117      *  <li>{@code pattern.matcher(text).replaceAll(StringUtils.EMPTY)}</li>
118      * </ul>
119      *
120      * <p>A {@code null} reference passed to this method is a no-op.</p>
121      *
122      * <pre>{@code
123      * StringUtils.removeAll(null, *)      = null
124      * StringUtils.removeAll("any", (Pattern) null)  = "any"
125      * StringUtils.removeAll("any", Pattern.compile(""))    = "any"
126      * StringUtils.removeAll("any", Pattern.compile(".*"))  = ""
127      * StringUtils.removeAll("any", Pattern.compile(".+"))  = ""
128      * StringUtils.removeAll("abc", Pattern.compile(".?"))  = ""
129      * StringUtils.removeAll("A<__>\n<__>B", Pattern.compile("<.*>"))      = "A\nB"
130      * StringUtils.removeAll("A<__>\n<__>B", Pattern.compile("(?s)<.*>"))  = "AB"
131      * StringUtils.removeAll("A<__>\n<__>B", Pattern.compile("<.*>", Pattern.DOTALL))  = "AB"
132      * StringUtils.removeAll("ABCabc123abc", Pattern.compile("[a-z]"))     = "ABC123"
133      * }</pre>
134      *
135      * @param text  text to remove from, may be null.
136      * @param regex  the regular expression to which this string is to be matched
137      * @return  the text with any removes processed,
138      *              {@code null} if null String input.
139      *
140      * @see #replaceAll(CharSequence, Pattern, String)
141      * @see java.util.regex.Matcher#replaceAll(String)
142      * @see java.util.regex.Pattern
143      * @deprecated Use {@link #removeAll(CharSequence, Pattern)}.
144      */
145     @Deprecated
146     public static String removeAll(final String text, final Pattern regex) {
147         return replaceAll((CharSequence) text, regex, StringUtils.EMPTY);
148     }
149 
150     /**
151      * Removes each substring of the text String that matches the given regular expression.
152      *
153      * This method is a {@code null} safe equivalent to:
154      * <ul>
155      *  <li>{@code text.replaceAll(regex, StringUtils.EMPTY)}</li>
156      *  <li>{@code Pattern.compile(regex).matcher(text).replaceAll(StringUtils.EMPTY)}</li>
157      * </ul>
158      *
159      * <p>A {@code null} reference passed to this method is a no-op.</p>
160      *
161      * <p>Unlike in the {@link #removePattern(CharSequence, String)} method, the {@link Pattern#DOTALL} option
162      * is NOT automatically added.
163      * To use the DOTALL option prepend {@code "(?s)"} to the regex.
164      * DOTALL is also known as single-line mode in Perl.</p>
165      *
166      * <pre>{@code
167      * StringUtils.removeAll(null, *)      = null
168      * StringUtils.removeAll("any", (String) null)  = "any"
169      * StringUtils.removeAll("any", "")    = "any"
170      * StringUtils.removeAll("any", ".*")  = ""
171      * StringUtils.removeAll("any", ".+")  = ""
172      * StringUtils.removeAll("abc", ".?")  = ""
173      * StringUtils.removeAll("A<__>\n<__>B", "<.*>")      = "A\nB"
174      * StringUtils.removeAll("A<__>\n<__>B", "(?s)<.*>")  = "AB"
175      * StringUtils.removeAll("ABCabc123abc", "[a-z]")     = "ABC123"
176      * }</pre>
177      *
178      * @param text  text to remove from, may be null
179      * @param regex  the regular expression to which this string is to be matched
180      * @return  the text with any removes processed,
181      *              {@code null} if null String input.
182      *
183      * @throws  java.util.regex.PatternSyntaxException
184      *              if the regular expression's syntax is invalid.
185      *
186      * @see #replaceAll(String, String, String)
187      * @see #removePattern(CharSequence, String)
188      * @see String#replaceAll(String, String)
189      * @see java.util.regex.Pattern
190      * @see java.util.regex.Pattern#DOTALL
191      */
192     public static String removeAll(final String text, final String regex) {
193         return replaceAll(text, regex, StringUtils.EMPTY);
194     }
195 
196     /**
197      * Removes the first substring of the text string that matches the given regular expression pattern.
198      *
199      * This method is a {@code null} safe equivalent to:
200      * <ul>
201      *  <li>{@code pattern.matcher(text).replaceFirst(StringUtils.EMPTY)}</li>
202      * </ul>
203      *
204      * <p>A {@code null} reference passed to this method is a no-op.</p>
205      *
206      * <pre>{@code
207      * StringUtils.removeFirst(null, *)      = null
208      * StringUtils.removeFirst("any", (Pattern) null)  = "any"
209      * StringUtils.removeFirst("any", Pattern.compile(""))    = "any"
210      * StringUtils.removeFirst("any", Pattern.compile(".*"))  = ""
211      * StringUtils.removeFirst("any", Pattern.compile(".+"))  = ""
212      * StringUtils.removeFirst("abc", Pattern.compile(".?"))  = "bc"
213      * StringUtils.removeFirst("A<__>\n<__>B", Pattern.compile("<.*>"))      = "A\n<__>B"
214      * StringUtils.removeFirst("A<__>\n<__>B", Pattern.compile("(?s)<.*>"))  = "AB"
215      * StringUtils.removeFirst("ABCabc123", Pattern.compile("[a-z]"))          = "ABCbc123"
216      * StringUtils.removeFirst("ABCabc123abc", Pattern.compile("[a-z]+"))      = "ABC123abc"
217      * }</pre>
218      *
219      * @param text  text to remove from, may be null.
220      * @param regex  the regular expression pattern to which this string is to be matched.
221      * @return  the text with the first replacement processed,
222      *              {@code null} if null String input.
223      *
224      * @see #replaceFirst(String, Pattern, String)
225      * @see java.util.regex.Matcher#replaceFirst(String)
226      * @see java.util.regex.Pattern
227      * @since 3.18.0
228      */
229     public static String removeFirst(final CharSequence text, final Pattern regex) {
230         return replaceFirst(text, regex, StringUtils.EMPTY);
231     }
232 
233     /**
234      * Removes the first substring of the text string that matches the given regular expression pattern.
235      *
236      * This method is a {@code null} safe equivalent to:
237      * <ul>
238      *  <li>{@code pattern.matcher(text).replaceFirst(StringUtils.EMPTY)}</li>
239      * </ul>
240      *
241      * <p>A {@code null} reference passed to this method is a no-op.</p>
242      *
243      * <pre>{@code
244      * StringUtils.removeFirst(null, *)      = null
245      * StringUtils.removeFirst("any", (Pattern) null)  = "any"
246      * StringUtils.removeFirst("any", Pattern.compile(""))    = "any"
247      * StringUtils.removeFirst("any", Pattern.compile(".*"))  = ""
248      * StringUtils.removeFirst("any", Pattern.compile(".+"))  = ""
249      * StringUtils.removeFirst("abc", Pattern.compile(".?"))  = "bc"
250      * StringUtils.removeFirst("A<__>\n<__>B", Pattern.compile("<.*>"))      = "A\n<__>B"
251      * StringUtils.removeFirst("A<__>\n<__>B", Pattern.compile("(?s)<.*>"))  = "AB"
252      * StringUtils.removeFirst("ABCabc123", Pattern.compile("[a-z]"))          = "ABCbc123"
253      * StringUtils.removeFirst("ABCabc123abc", Pattern.compile("[a-z]+"))      = "ABC123abc"
254      * }</pre>
255      *
256      * @param text  text to remove from, may be null.
257      * @param regex  the regular expression pattern to which this string is to be matched.
258      * @return  the text with the first replacement processed,
259      *              {@code null} if null String input.
260      *
261      * @see #replaceFirst(String, Pattern, String)
262      * @see java.util.regex.Matcher#replaceFirst(String)
263      * @see java.util.regex.Pattern
264      * @deprecated Use {@link #removeFirst(CharSequence, Pattern)}.
265      */
266     @Deprecated
267     public static String removeFirst(final String text, final Pattern regex) {
268         return replaceFirst(text, regex, StringUtils.EMPTY);
269     }
270 
271     /**
272      * Removes the first substring of the text string that matches the given regular expression.
273      *
274      * This method is a {@code null} safe equivalent to:
275      * <ul>
276      *  <li>{@code text.replaceFirst(regex, StringUtils.EMPTY)}</li>
277      *  <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(StringUtils.EMPTY)}</li>
278      * </ul>
279      *
280      * <p>A {@code null} reference passed to this method is a no-op.</p>
281      *
282      * <p>The {@link Pattern#DOTALL} option is NOT automatically added.
283      * To use the DOTALL option prepend {@code "(?s)"} to the regex.
284      * DOTALL is also known as single-line mode in Perl.</p>
285      *
286      * <pre>{@code
287      * StringUtils.removeFirst(null, *)      = null
288      * StringUtils.removeFirst("any", (String) null)  = "any"
289      * StringUtils.removeFirst("any", "")    = "any"
290      * StringUtils.removeFirst("any", ".*")  = ""
291      * StringUtils.removeFirst("any", ".+")  = ""
292      * StringUtils.removeFirst("abc", ".?")  = "bc"
293      * StringUtils.removeFirst("A<__>\n<__>B", "<.*>")      = "A\n<__>B"
294      * StringUtils.removeFirst("A<__>\n<__>B", "(?s)<.*>")  = "AB"
295      * StringUtils.removeFirst("ABCabc123", "[a-z]")          = "ABCbc123"
296      * StringUtils.removeFirst("ABCabc123abc", "[a-z]+")      = "ABC123abc"
297      * }</pre>
298      *
299      * @param text  text to remove from, may be null.
300      * @param regex  the regular expression to which this string is to be matched.
301      * @return  the text with the first replacement processed,
302      *              {@code null} if null String input.
303      *
304      * @throws  java.util.regex.PatternSyntaxException
305      *              if the regular expression's syntax is invalid.
306      *
307      * @see #replaceFirst(String, String, String)
308      * @see String#replaceFirst(String, String)
309      * @see java.util.regex.Pattern
310      * @see java.util.regex.Pattern#DOTALL
311      */
312     public static String removeFirst(final String text, final String regex) {
313         return replaceFirst(text, regex, StringUtils.EMPTY);
314     }
315 
316     /**
317      * Removes each substring of the source String that matches the given regular expression using the DOTALL option.
318      *
319      * This call is a {@code null} safe equivalent to:
320      * <ul>
321      * <li>{@code text.replaceAll(&quot;(?s)&quot; + regex, StringUtils.EMPTY)}</li>
322      * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(text).replaceAll(StringUtils.EMPTY)}</li>
323      * </ul>
324      *
325      * <p>A {@code null} reference passed to this method is a no-op.</p>
326      *
327      * <pre>{@code
328      * StringUtils.removePattern(null, *)       = null
329      * StringUtils.removePattern("any", (String) null)   = "any"
330      * StringUtils.removePattern("A<__>\n<__>B", "<.*>")  = "AB"
331      * StringUtils.removePattern("ABCabc123", "[a-z]")    = "ABC123"
332      * }</pre>
333      *
334      * @param text
335      *            the source string.
336      * @param regex
337      *            the regular expression to which this string is to be matched.
338      * @return The resulting {@link String}.
339      * @see #replacePattern(CharSequence, String, String)
340      * @see String#replaceAll(String, String)
341      * @see Pattern#DOTALL
342      * @since 3.18.0
343      */
344     public static String removePattern(final CharSequence text, final String regex) {
345         return replacePattern(text, regex, StringUtils.EMPTY);
346     }
347 
348     /**
349      * Removes each substring of the source String that matches the given regular expression using the DOTALL option.
350      *
351      * This call is a {@code null} safe equivalent to:
352      * <ul>
353      * <li>{@code text.replaceAll(&quot;(?s)&quot; + regex, StringUtils.EMPTY)}</li>
354      * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(text).replaceAll(StringUtils.EMPTY)}</li>
355      * </ul>
356      *
357      * <p>A {@code null} reference passed to this method is a no-op.</p>
358      *
359      * <pre>{@code
360      * StringUtils.removePattern(null, *)       = null
361      * StringUtils.removePattern("any", (String) null)   = "any"
362      * StringUtils.removePattern("A<__>\n<__>B", "<.*>")  = "AB"
363      * StringUtils.removePattern("ABCabc123", "[a-z]")    = "ABC123"
364      * }</pre>
365      *
366      * @param text
367      *            the source string.
368      * @param regex
369      *            the regular expression to which this string is to be matched.
370      * @return The resulting {@link String}.
371      * @see #replacePattern(CharSequence, String, String)
372      * @see String#replaceAll(String, String)
373      * @see Pattern#DOTALL
374      * @deprecated Use {@link #removePattern(CharSequence, String)}.
375      */
376     @Deprecated
377     public static String removePattern(final String text, final String regex) {
378         return replacePattern((CharSequence) text, regex, StringUtils.EMPTY);
379     }
380 
381     /**
382      * Replaces each substring of the text String that matches the given regular expression pattern with the given replacement.
383      *
384      * This method is a {@code null} safe equivalent to:
385      * <ul>
386      *  <li>{@code pattern.matcher(text).replaceAll(replacement)}</li>
387      * </ul>
388      *
389      * <p>A {@code null} reference passed to this method is a no-op.</p>
390      *
391      * <pre>{@code
392      * StringUtils.replaceAll(null, *, *)       = null
393      * StringUtils.replaceAll("any", (Pattern) null, *)   = "any"
394      * StringUtils.replaceAll("any", *, null)   = "any"
395      * StringUtils.replaceAll("", Pattern.compile(""), "zzz")    = "zzz"
396      * StringUtils.replaceAll("", Pattern.compile(".*"), "zzz")  = "zzz"
397      * StringUtils.replaceAll("", Pattern.compile(".+"), "zzz")  = ""
398      * StringUtils.replaceAll("abc", Pattern.compile(""), "ZZ")  = "ZZaZZbZZcZZ"
399      * StringUtils.replaceAll("<__>\n<__>", Pattern.compile("<.*>"), "z")                 = "z\nz"
400      * StringUtils.replaceAll("<__>\n<__>", Pattern.compile("<.*>", Pattern.DOTALL), "z") = "z"
401      * StringUtils.replaceAll("<__>\n<__>", Pattern.compile("(?s)<.*>"), "z")             = "z"
402      * StringUtils.replaceAll("ABCabc123", Pattern.compile("[a-z]"), "_")       = "ABC___123"
403      * StringUtils.replaceAll("ABCabc123", Pattern.compile("[^A-Z0-9]+"), "_")  = "ABC_123"
404      * StringUtils.replaceAll("ABCabc123", Pattern.compile("[^A-Z0-9]+"), "")   = "ABC123"
405      * StringUtils.replaceAll("Lorem ipsum  dolor   sit", Pattern.compile("( +)([a-z]+)"), "_$2")  = "Lorem_ipsum_dolor_sit"
406      * }</pre>
407      *
408      * @param text  text to search and replace in, may be null.
409      * @param regex  the regular expression pattern to which this string is to be matched.
410      * @param replacement  the string to be substituted for each match.
411      * @return  the text with any replacements processed,
412      *              {@code null} if null String input.
413      * @see java.util.regex.Matcher#replaceAll(String)
414      * @see java.util.regex.Pattern
415      */
416     public static String replaceAll(final CharSequence text, final Pattern regex, final String replacement) {
417         if (ObjectUtils.anyNull(text, regex, replacement)) {
418             return toStringOrNull(text);
419         }
420         return regex.matcher(text).replaceAll(replacement);
421     }
422 
423     /**
424      * Replaces each substring of the text String that matches the given regular expression pattern with the given replacement.
425      *
426      * This method is a {@code null} safe equivalent to:
427      * <ul>
428      *  <li>{@code pattern.matcher(text).replaceAll(replacement)}</li>
429      * </ul>
430      *
431      * <p>A {@code null} reference passed to this method is a no-op.</p>
432      *
433      * <pre>{@code
434      * StringUtils.replaceAll(null, *, *)       = null
435      * StringUtils.replaceAll("any", (Pattern) null, *)   = "any"
436      * StringUtils.replaceAll("any", *, null)   = "any"
437      * StringUtils.replaceAll("", Pattern.compile(""), "zzz")    = "zzz"
438      * StringUtils.replaceAll("", Pattern.compile(".*"), "zzz")  = "zzz"
439      * StringUtils.replaceAll("", Pattern.compile(".+"), "zzz")  = ""
440      * StringUtils.replaceAll("abc", Pattern.compile(""), "ZZ")  = "ZZaZZbZZcZZ"
441      * StringUtils.replaceAll("<__>\n<__>", Pattern.compile("<.*>"), "z")                 = "z\nz"
442      * StringUtils.replaceAll("<__>\n<__>", Pattern.compile("<.*>", Pattern.DOTALL), "z") = "z"
443      * StringUtils.replaceAll("<__>\n<__>", Pattern.compile("(?s)<.*>"), "z")             = "z"
444      * StringUtils.replaceAll("ABCabc123", Pattern.compile("[a-z]"), "_")       = "ABC___123"
445      * StringUtils.replaceAll("ABCabc123", Pattern.compile("[^A-Z0-9]+"), "_")  = "ABC_123"
446      * StringUtils.replaceAll("ABCabc123", Pattern.compile("[^A-Z0-9]+"), "")   = "ABC123"
447      * StringUtils.replaceAll("Lorem ipsum  dolor   sit", Pattern.compile("( +)([a-z]+)"), "_$2")  = "Lorem_ipsum_dolor_sit"
448      * }</pre>
449      *
450      * @param text  text to search and replace in, may be null.
451      * @param regex  the regular expression pattern to which this string is to be matched.
452      * @param replacement  the string to be substituted for each match.
453      * @return  the text with any replacements processed,
454      *              {@code null} if null String input.
455      * @see java.util.regex.Matcher#replaceAll(String)
456      * @see java.util.regex.Pattern
457      * @deprecated Use {@link #replaceAll(CharSequence, Pattern, String)}.
458      */
459     @Deprecated
460     public static String replaceAll(final String text, final Pattern regex, final String replacement) {
461         return replaceAll((CharSequence) text, regex, replacement);
462     }
463 
464     /**
465      * Replaces each substring of the text String that matches the given regular expression
466      * with the given replacement.
467      *
468      * This method is a {@code null} safe equivalent to:
469      * <ul>
470      *  <li>{@code text.replaceAll(regex, replacement)}</li>
471      *  <li>{@code Pattern.compile(regex).matcher(text).replaceAll(replacement)}</li>
472      * </ul>
473      *
474      * <p>A {@code null} reference passed to this method is a no-op.</p>
475      *
476      * <p>Unlike in the {@link #replacePattern(CharSequence, String, String)} method, the {@link Pattern#DOTALL} option
477      * is NOT automatically added.
478      * To use the DOTALL option prepend {@code "(?s)"} to the regex.
479      * DOTALL is also known as single-line mode in Perl.</p>
480      *
481      * <pre>{@code
482      * StringUtils.replaceAll(null, *, *)       = null
483      * StringUtils.replaceAll("any", (String) null, *)   = "any"
484      * StringUtils.replaceAll("any", *, null)   = "any"
485      * StringUtils.replaceAll("", "", "zzz")    = "zzz"
486      * StringUtils.replaceAll("", ".*", "zzz")  = "zzz"
487      * StringUtils.replaceAll("", ".+", "zzz")  = ""
488      * StringUtils.replaceAll("abc", "", "ZZ")  = "ZZaZZbZZcZZ"
489      * StringUtils.replaceAll("<__>\n<__>", "<.*>", "z")      = "z\nz"
490      * StringUtils.replaceAll("<__>\n<__>", "(?s)<.*>", "z")  = "z"
491      * StringUtils.replaceAll("ABCabc123", "[a-z]", "_")       = "ABC___123"
492      * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "_")  = "ABC_123"
493      * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "")   = "ABC123"
494      * StringUtils.replaceAll("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
495      * }</pre>
496      *
497      * @param text  text to search and replace in, may be null.
498      * @param regex  the regular expression to which this string is to be matched.
499      * @param replacement  the string to be substituted for each match.
500      * @return  the text with any replacements processed,
501      *              {@code null} if null String input.
502      * @throws  java.util.regex.PatternSyntaxException
503      *              if the regular expression's syntax is invalid.
504      * @see #replacePattern(String, String, String)
505      * @see String#replaceAll(String, String)
506      * @see java.util.regex.Pattern
507      * @see java.util.regex.Pattern#DOTALL
508      */
509     public static String replaceAll(final String text, final String regex, final String replacement) {
510         if (ObjectUtils.anyNull(text, regex, replacement)) {
511             return text;
512         }
513         return text.replaceAll(regex, replacement);
514     }
515 
516     /**
517      * Replaces the first substring of the text string that matches the given regular expression pattern
518      * with the given replacement.
519      *
520      * This method is a {@code null} safe equivalent to:
521      * <ul>
522      *  <li>{@code pattern.matcher(text).replaceFirst(replacement)}</li>
523      * </ul>
524      *
525      * <p>A {@code null} reference passed to this method is a no-op.</p>
526      *
527      * <pre>{@code
528      * StringUtils.replaceFirst(null, *, *)       = null
529      * StringUtils.replaceFirst("any", (Pattern) null, *)   = "any"
530      * StringUtils.replaceFirst("any", *, null)   = "any"
531      * StringUtils.replaceFirst("", Pattern.compile(""), "zzz")    = "zzz"
532      * StringUtils.replaceFirst("", Pattern.compile(".*"), "zzz")  = "zzz"
533      * StringUtils.replaceFirst("", Pattern.compile(".+"), "zzz")  = ""
534      * StringUtils.replaceFirst("abc", Pattern.compile(""), "ZZ")  = "ZZabc"
535      * StringUtils.replaceFirst("<__>\n<__>", Pattern.compile("<.*>"), "z")      = "z\n<__>"
536      * StringUtils.replaceFirst("<__>\n<__>", Pattern.compile("(?s)<.*>"), "z")  = "z"
537      * StringUtils.replaceFirst("ABCabc123", Pattern.compile("[a-z]"), "_")          = "ABC_bc123"
538      * StringUtils.replaceFirst("ABCabc123abc", Pattern.compile("[^A-Z0-9]+"), "_")  = "ABC_123abc"
539      * StringUtils.replaceFirst("ABCabc123abc", Pattern.compile("[^A-Z0-9]+"), "")   = "ABC123abc"
540      * StringUtils.replaceFirst("Lorem ipsum  dolor   sit", Pattern.compile("( +)([a-z]+)"), "_$2")  = "Lorem_ipsum  dolor   sit"
541      * }</pre>
542      *
543      * @param text  text to search and replace in, may be null.
544      * @param regex  the regular expression pattern to which this string is to be matched.
545      * @param replacement  the string to be substituted for the first match
546      * @return  the text with the first replacement processed,
547      *              {@code null} if null String input.
548      * @see java.util.regex.Matcher#replaceFirst(String)
549      * @see java.util.regex.Pattern
550      * @since 3.18.0
551      */
552     public static String replaceFirst(final CharSequence text, final Pattern regex, final String replacement) {
553         if (text == null || regex == null || replacement == null) {
554             return toStringOrNull(text);
555         }
556         return regex.matcher(text).replaceFirst(replacement);
557     }
558 
559     /**
560      * Replaces the first substring of the text string that matches the given regular expression pattern
561      * with the given replacement.
562      *
563      * This method is a {@code null} safe equivalent to:
564      * <ul>
565      *  <li>{@code pattern.matcher(text).replaceFirst(replacement)}</li>
566      * </ul>
567      *
568      * <p>A {@code null} reference passed to this method is a no-op.</p>
569      *
570      * <pre>{@code
571      * StringUtils.replaceFirst(null, *, *)       = null
572      * StringUtils.replaceFirst("any", (Pattern) null, *)   = "any"
573      * StringUtils.replaceFirst("any", *, null)   = "any"
574      * StringUtils.replaceFirst("", Pattern.compile(""), "zzz")    = "zzz"
575      * StringUtils.replaceFirst("", Pattern.compile(".*"), "zzz")  = "zzz"
576      * StringUtils.replaceFirst("", Pattern.compile(".+"), "zzz")  = ""
577      * StringUtils.replaceFirst("abc", Pattern.compile(""), "ZZ")  = "ZZabc"
578      * StringUtils.replaceFirst("<__>\n<__>", Pattern.compile("<.*>"), "z")      = "z\n<__>"
579      * StringUtils.replaceFirst("<__>\n<__>", Pattern.compile("(?s)<.*>"), "z")  = "z"
580      * StringUtils.replaceFirst("ABCabc123", Pattern.compile("[a-z]"), "_")          = "ABC_bc123"
581      * StringUtils.replaceFirst("ABCabc123abc", Pattern.compile("[^A-Z0-9]+"), "_")  = "ABC_123abc"
582      * StringUtils.replaceFirst("ABCabc123abc", Pattern.compile("[^A-Z0-9]+"), "")   = "ABC123abc"
583      * StringUtils.replaceFirst("Lorem ipsum  dolor   sit", Pattern.compile("( +)([a-z]+)"), "_$2")  = "Lorem_ipsum  dolor   sit"
584      * }</pre>
585      *
586      * @param text  text to search and replace in, may be null.
587      * @param regex  the regular expression pattern to which this string is to be matched.
588      * @param replacement  the string to be substituted for the first match.
589      * @return  the text with the first replacement processed,
590      *              {@code null} if null String input.
591      * @see java.util.regex.Matcher#replaceFirst(String)
592      * @see java.util.regex.Pattern
593      * @deprecated Use {@link #replaceFirst(CharSequence, Pattern, String)}.
594      */
595     @Deprecated
596     public static String replaceFirst(final String text, final Pattern regex, final String replacement) {
597         return replaceFirst((CharSequence) text, regex, replacement);
598     }
599 
600     /**
601      * Replaces the first substring of the text string that matches the given regular expression
602      * with the given replacement.
603      *
604      * This method is a {@code null} safe equivalent to:
605      * <ul>
606      *  <li>{@code text.replaceFirst(regex, replacement)}</li>
607      *  <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(replacement)}</li>
608      * </ul>
609      *
610      * <p>A {@code null} reference passed to this method is a no-op.</p>
611      *
612      * <p>The {@link Pattern#DOTALL} option is NOT automatically added.
613      * To use the DOTALL option prepend {@code "(?s)"} to the regex.
614      * DOTALL is also known as single-line mode in Perl.</p>
615      *
616      * <pre>{@code
617      * StringUtils.replaceFirst(null, *, *)       = null
618      * StringUtils.replaceFirst("any", (String) null, *)   = "any"
619      * StringUtils.replaceFirst("any", *, null)   = "any"
620      * StringUtils.replaceFirst("", "", "zzz")    = "zzz"
621      * StringUtils.replaceFirst("", ".*", "zzz")  = "zzz"
622      * StringUtils.replaceFirst("", ".+", "zzz")  = ""
623      * StringUtils.replaceFirst("abc", "", "ZZ")  = "ZZabc"
624      * StringUtils.replaceFirst("<__>\n<__>", "<.*>", "z")      = "z\n<__>"
625      * StringUtils.replaceFirst("<__>\n<__>", "(?s)<.*>", "z")  = "z"
626      * StringUtils.replaceFirst("ABCabc123", "[a-z]", "_")          = "ABC_bc123"
627      * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "_")  = "ABC_123abc"
628      * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "")   = "ABC123abc"
629      * StringUtils.replaceFirst("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum  dolor   sit"
630      * }</pre>
631      *
632      * @param text  text to search and replace in, may be null.
633      * @param regex  the regular expression to which this string is to be matched.
634      * @param replacement  the string to be substituted for the first match.
635      * @return  the text with the first replacement processed,
636      *              {@code null} if null String input.
637      * @throws  java.util.regex.PatternSyntaxException
638      *              if the regular expression's syntax is invalid.
639      * @see String#replaceFirst(String, String)
640      * @see java.util.regex.Pattern
641      * @see java.util.regex.Pattern#DOTALL
642      */
643     public static String replaceFirst(final String text, final String regex, final String replacement) {
644         if (text == null || regex == null || replacement == null) {
645             return text;
646         }
647         return text.replaceFirst(regex, replacement);
648     }
649 
650     /**
651      * Replaces each substring of the source String that matches the given regular expression with the given
652      * replacement using the {@link Pattern#DOTALL} option. DOTALL is also known as single-line mode in Perl.
653      *
654      * This call is a {@code null} safe equivalent to:
655      * <ul>
656      * <li>{@code text.replaceAll(&quot;(?s)&quot; + regex, replacement)}</li>
657      * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(text).replaceAll(replacement)}</li>
658      * </ul>
659      *
660      * <p>A {@code null} reference passed to this method is a no-op.</p>
661      *
662      * <pre>{@code
663      * StringUtils.replacePattern(null, *, *)       = null
664      * StringUtils.replacePattern("any", (String) null, *)   = "any"
665      * StringUtils.replacePattern("any", *, null)   = "any"
666      * StringUtils.replacePattern("", "", "zzz")    = "zzz"
667      * StringUtils.replacePattern("", ".*", "zzz")  = "zzz"
668      * StringUtils.replacePattern("", ".+", "zzz")  = ""
669      * StringUtils.replacePattern("<__>\n<__>", "<.*>", "z")       = "z"
670      * StringUtils.replacePattern("ABCabc123", "[a-z]", "_")       = "ABC___123"
671      * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "_")  = "ABC_123"
672      * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "")   = "ABC123"
673      * StringUtils.replacePattern("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
674      * }</pre>
675      *
676      * @param text
677      *            the source string.
678      * @param regex
679      *            the regular expression to which this string is to be matched.
680      * @param replacement
681      *            the string to be substituted for each match.
682      * @return The resulting {@link String}.
683      * @see #replaceAll(String, String, String)
684      * @see String#replaceAll(String, String)
685      * @see Pattern#DOTALL
686      * @since 3.18.0
687      */
688     public static String replacePattern(final CharSequence text, final String regex, final String replacement) {
689         if (ObjectUtils.anyNull(text, regex, replacement)) {
690             return toStringOrNull(text);
691         }
692         return dotAllMatcher(regex, text).replaceAll(replacement);
693     }
694 
695     /**
696      * Replaces each substring of the source String that matches the given regular expression with the given
697      * replacement using the {@link Pattern#DOTALL} option. DOTALL is also known as single-line mode in Perl.
698      *
699      * This call is a {@code null} safe equivalent to:
700      * <ul>
701      * <li>{@code text.replaceAll(&quot;(?s)&quot; + regex, replacement)}</li>
702      * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(text).replaceAll(replacement)}</li>
703      * </ul>
704      *
705      * <p>A {@code null} reference passed to this method is a no-op.</p>
706      *
707      * <pre>{@code
708      * StringUtils.replacePattern(null, *, *)       = null
709      * StringUtils.replacePattern("any", (String) null, *)   = "any"
710      * StringUtils.replacePattern("any", *, null)   = "any"
711      * StringUtils.replacePattern("", "", "zzz")    = "zzz"
712      * StringUtils.replacePattern("", ".*", "zzz")  = "zzz"
713      * StringUtils.replacePattern("", ".+", "zzz")  = ""
714      * StringUtils.replacePattern("<__>\n<__>", "<.*>", "z")       = "z"
715      * StringUtils.replacePattern("ABCabc123", "[a-z]", "_")       = "ABC___123"
716      * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "_")  = "ABC_123"
717      * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "")   = "ABC123"
718      * StringUtils.replacePattern("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
719      * }</pre>
720      *
721      * @param text
722      *            the source string.
723      * @param regex
724      *            the regular expression to which this string is to be matched.
725      * @param replacement
726      *            the string to be substituted for each match.
727      * @return The resulting {@link String}.
728      * @see #replaceAll(String, String, String)
729      * @see String#replaceAll(String, String)
730      * @see Pattern#DOTALL
731      * @deprecated Use {@link #replacePattern(CharSequence, String, String)}.
732      */
733     @Deprecated
734     public static String replacePattern(final String text, final String regex, final String replacement) {
735         return replacePattern((CharSequence) text, regex, replacement);
736     }
737 
738     private static String toStringOrNull(final CharSequence text) {
739         return Objects.toString(text, null);
740     }
741 
742     /**
743      * Make private in 4.0.
744      *
745      * @deprecated TODO Make private in 4.0.
746      */
747     @Deprecated
748     public RegExUtils() {
749         // empty
750     }
751 }