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      *
414      * @see java.util.regex.Matcher#replaceAll(String)
415      * @see java.util.regex.Pattern
416      */
417     public static String replaceAll(final CharSequence text, final Pattern regex, final String replacement) {
418         if (ObjectUtils.anyNull(text, regex, replacement)) {
419             return toStringOrNull(text);
420         }
421         return regex.matcher(text).replaceAll(replacement);
422     }
423 
424     /**
425      * Replaces each substring of the text String that matches the given regular expression pattern with the given replacement.
426      *
427      * This method is a {@code null} safe equivalent to:
428      * <ul>
429      *  <li>{@code pattern.matcher(text).replaceAll(replacement)}</li>
430      * </ul>
431      *
432      * <p>A {@code null} reference passed to this method is a no-op.</p>
433      *
434      * <pre>{@code
435      * StringUtils.replaceAll(null, *, *)       = null
436      * StringUtils.replaceAll("any", (Pattern) null, *)   = "any"
437      * StringUtils.replaceAll("any", *, null)   = "any"
438      * StringUtils.replaceAll("", Pattern.compile(""), "zzz")    = "zzz"
439      * StringUtils.replaceAll("", Pattern.compile(".*"), "zzz")  = "zzz"
440      * StringUtils.replaceAll("", Pattern.compile(".+"), "zzz")  = ""
441      * StringUtils.replaceAll("abc", Pattern.compile(""), "ZZ")  = "ZZaZZbZZcZZ"
442      * StringUtils.replaceAll("<__>\n<__>", Pattern.compile("<.*>"), "z")                 = "z\nz"
443      * StringUtils.replaceAll("<__>\n<__>", Pattern.compile("<.*>", Pattern.DOTALL), "z") = "z"
444      * StringUtils.replaceAll("<__>\n<__>", Pattern.compile("(?s)<.*>"), "z")             = "z"
445      * StringUtils.replaceAll("ABCabc123", Pattern.compile("[a-z]"), "_")       = "ABC___123"
446      * StringUtils.replaceAll("ABCabc123", Pattern.compile("[^A-Z0-9]+"), "_")  = "ABC_123"
447      * StringUtils.replaceAll("ABCabc123", Pattern.compile("[^A-Z0-9]+"), "")   = "ABC123"
448      * StringUtils.replaceAll("Lorem ipsum  dolor   sit", Pattern.compile("( +)([a-z]+)"), "_$2")  = "Lorem_ipsum_dolor_sit"
449      * }</pre>
450      *
451      * @param text  text to search and replace in, may be null
452      * @param regex  the regular expression pattern to which this string is to be matched
453      * @param replacement  the string to be substituted for each match
454      * @return  the text with any replacements processed,
455      *              {@code null} if null String input
456      *
457      * @see java.util.regex.Matcher#replaceAll(String)
458      * @see java.util.regex.Pattern
459      * @deprecated Use {@link #replaceAll(CharSequence, Pattern, String)}.
460      */
461     @Deprecated
462     public static String replaceAll(final String text, final Pattern regex, final String replacement) {
463         return replaceAll((CharSequence) text, regex, replacement);
464     }
465 
466     /**
467      * Replaces each substring of the text String that matches the given regular expression
468      * with the given replacement.
469      *
470      * This method is a {@code null} safe equivalent to:
471      * <ul>
472      *  <li>{@code text.replaceAll(regex, replacement)}</li>
473      *  <li>{@code Pattern.compile(regex).matcher(text).replaceAll(replacement)}</li>
474      * </ul>
475      *
476      * <p>A {@code null} reference passed to this method is a no-op.</p>
477      *
478      * <p>Unlike in the {@link #replacePattern(CharSequence, String, String)} method, the {@link Pattern#DOTALL} option
479      * is NOT automatically added.
480      * To use the DOTALL option prepend {@code "(?s)"} to the regex.
481      * DOTALL is also known as single-line mode in Perl.</p>
482      *
483      * <pre>{@code
484      * StringUtils.replaceAll(null, *, *)       = null
485      * StringUtils.replaceAll("any", (String) null, *)   = "any"
486      * StringUtils.replaceAll("any", *, null)   = "any"
487      * StringUtils.replaceAll("", "", "zzz")    = "zzz"
488      * StringUtils.replaceAll("", ".*", "zzz")  = "zzz"
489      * StringUtils.replaceAll("", ".+", "zzz")  = ""
490      * StringUtils.replaceAll("abc", "", "ZZ")  = "ZZaZZbZZcZZ"
491      * StringUtils.replaceAll("<__>\n<__>", "<.*>", "z")      = "z\nz"
492      * StringUtils.replaceAll("<__>\n<__>", "(?s)<.*>", "z")  = "z"
493      * StringUtils.replaceAll("ABCabc123", "[a-z]", "_")       = "ABC___123"
494      * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "_")  = "ABC_123"
495      * StringUtils.replaceAll("ABCabc123", "[^A-Z0-9]+", "")   = "ABC123"
496      * StringUtils.replaceAll("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
497      * }</pre>
498      *
499      * @param text  text to search and replace in, may be null
500      * @param regex  the regular expression to which this string is to be matched
501      * @param replacement  the string to be substituted for each match
502      * @return  the text with any replacements processed,
503      *              {@code null} if null String input
504      *
505      * @throws  java.util.regex.PatternSyntaxException
506      *              if the regular expression's syntax is invalid
507      *
508      * @see #replacePattern(String, String, String)
509      * @see String#replaceAll(String, String)
510      * @see java.util.regex.Pattern
511      * @see java.util.regex.Pattern#DOTALL
512      */
513     public static String replaceAll(final String text, final String regex, final String replacement) {
514         if (ObjectUtils.anyNull(text, regex, replacement)) {
515             return text;
516         }
517         return text.replaceAll(regex, replacement);
518     }
519 
520     /**
521      * Replaces the first substring of the text string that matches the given regular expression pattern
522      * with the given replacement.
523      *
524      * This method is a {@code null} safe equivalent to:
525      * <ul>
526      *  <li>{@code pattern.matcher(text).replaceFirst(replacement)}</li>
527      * </ul>
528      *
529      * <p>A {@code null} reference passed to this method is a no-op.</p>
530      *
531      * <pre>{@code
532      * StringUtils.replaceFirst(null, *, *)       = null
533      * StringUtils.replaceFirst("any", (Pattern) null, *)   = "any"
534      * StringUtils.replaceFirst("any", *, null)   = "any"
535      * StringUtils.replaceFirst("", Pattern.compile(""), "zzz")    = "zzz"
536      * StringUtils.replaceFirst("", Pattern.compile(".*"), "zzz")  = "zzz"
537      * StringUtils.replaceFirst("", Pattern.compile(".+"), "zzz")  = ""
538      * StringUtils.replaceFirst("abc", Pattern.compile(""), "ZZ")  = "ZZabc"
539      * StringUtils.replaceFirst("<__>\n<__>", Pattern.compile("<.*>"), "z")      = "z\n<__>"
540      * StringUtils.replaceFirst("<__>\n<__>", Pattern.compile("(?s)<.*>"), "z")  = "z"
541      * StringUtils.replaceFirst("ABCabc123", Pattern.compile("[a-z]"), "_")          = "ABC_bc123"
542      * StringUtils.replaceFirst("ABCabc123abc", Pattern.compile("[^A-Z0-9]+"), "_")  = "ABC_123abc"
543      * StringUtils.replaceFirst("ABCabc123abc", Pattern.compile("[^A-Z0-9]+"), "")   = "ABC123abc"
544      * StringUtils.replaceFirst("Lorem ipsum  dolor   sit", Pattern.compile("( +)([a-z]+)"), "_$2")  = "Lorem_ipsum  dolor   sit"
545      * }</pre>
546      *
547      * @param text  text to search and replace in, may be null
548      * @param regex  the regular expression pattern to which this string is to be matched
549      * @param replacement  the string to be substituted for the first match
550      * @return  the text with the first replacement processed,
551      *              {@code null} if null String input
552      *
553      * @see java.util.regex.Matcher#replaceFirst(String)
554      * @see java.util.regex.Pattern
555      * @since 3.18.0
556      */
557     public static String replaceFirst(final CharSequence text, final Pattern regex, final String replacement) {
558         if (text == null || regex == null || replacement == null) {
559             return toStringOrNull(text);
560         }
561         return regex.matcher(text).replaceFirst(replacement);
562     }
563 
564     /**
565      * Replaces the first substring of the text string that matches the given regular expression pattern
566      * with the given replacement.
567      *
568      * This method is a {@code null} safe equivalent to:
569      * <ul>
570      *  <li>{@code pattern.matcher(text).replaceFirst(replacement)}</li>
571      * </ul>
572      *
573      * <p>A {@code null} reference passed to this method is a no-op.</p>
574      *
575      * <pre>{@code
576      * StringUtils.replaceFirst(null, *, *)       = null
577      * StringUtils.replaceFirst("any", (Pattern) null, *)   = "any"
578      * StringUtils.replaceFirst("any", *, null)   = "any"
579      * StringUtils.replaceFirst("", Pattern.compile(""), "zzz")    = "zzz"
580      * StringUtils.replaceFirst("", Pattern.compile(".*"), "zzz")  = "zzz"
581      * StringUtils.replaceFirst("", Pattern.compile(".+"), "zzz")  = ""
582      * StringUtils.replaceFirst("abc", Pattern.compile(""), "ZZ")  = "ZZabc"
583      * StringUtils.replaceFirst("<__>\n<__>", Pattern.compile("<.*>"), "z")      = "z\n<__>"
584      * StringUtils.replaceFirst("<__>\n<__>", Pattern.compile("(?s)<.*>"), "z")  = "z"
585      * StringUtils.replaceFirst("ABCabc123", Pattern.compile("[a-z]"), "_")          = "ABC_bc123"
586      * StringUtils.replaceFirst("ABCabc123abc", Pattern.compile("[^A-Z0-9]+"), "_")  = "ABC_123abc"
587      * StringUtils.replaceFirst("ABCabc123abc", Pattern.compile("[^A-Z0-9]+"), "")   = "ABC123abc"
588      * StringUtils.replaceFirst("Lorem ipsum  dolor   sit", Pattern.compile("( +)([a-z]+)"), "_$2")  = "Lorem_ipsum  dolor   sit"
589      * }</pre>
590      *
591      * @param text  text to search and replace in, may be null
592      * @param regex  the regular expression pattern to which this string is to be matched
593      * @param replacement  the string to be substituted for the first match
594      * @return  the text with the first replacement processed,
595      *              {@code null} if null String input
596      *
597      * @see java.util.regex.Matcher#replaceFirst(String)
598      * @see java.util.regex.Pattern
599      * @deprecated Use {@link #replaceFirst(CharSequence, Pattern, String)}.
600      */
601     @Deprecated
602     public static String replaceFirst(final String text, final Pattern regex, final String replacement) {
603         return replaceFirst((CharSequence) text, regex, replacement);
604     }
605 
606     /**
607      * Replaces the first substring of the text string that matches the given regular expression
608      * with the given replacement.
609      *
610      * This method is a {@code null} safe equivalent to:
611      * <ul>
612      *  <li>{@code text.replaceFirst(regex, replacement)}</li>
613      *  <li>{@code Pattern.compile(regex).matcher(text).replaceFirst(replacement)}</li>
614      * </ul>
615      *
616      * <p>A {@code null} reference passed to this method is a no-op.</p>
617      *
618      * <p>The {@link Pattern#DOTALL} option is NOT automatically added.
619      * To use the DOTALL option prepend {@code "(?s)"} to the regex.
620      * DOTALL is also known as single-line mode in Perl.</p>
621      *
622      * <pre>{@code
623      * StringUtils.replaceFirst(null, *, *)       = null
624      * StringUtils.replaceFirst("any", (String) null, *)   = "any"
625      * StringUtils.replaceFirst("any", *, null)   = "any"
626      * StringUtils.replaceFirst("", "", "zzz")    = "zzz"
627      * StringUtils.replaceFirst("", ".*", "zzz")  = "zzz"
628      * StringUtils.replaceFirst("", ".+", "zzz")  = ""
629      * StringUtils.replaceFirst("abc", "", "ZZ")  = "ZZabc"
630      * StringUtils.replaceFirst("<__>\n<__>", "<.*>", "z")      = "z\n<__>"
631      * StringUtils.replaceFirst("<__>\n<__>", "(?s)<.*>", "z")  = "z"
632      * StringUtils.replaceFirst("ABCabc123", "[a-z]", "_")          = "ABC_bc123"
633      * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "_")  = "ABC_123abc"
634      * StringUtils.replaceFirst("ABCabc123abc", "[^A-Z0-9]+", "")   = "ABC123abc"
635      * StringUtils.replaceFirst("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum  dolor   sit"
636      * }</pre>
637      *
638      * @param text  text to search and replace in, may be null
639      * @param regex  the regular expression to which this string is to be matched
640      * @param replacement  the string to be substituted for the first match
641      * @return  the text with the first replacement processed,
642      *              {@code null} if null String input
643      *
644      * @throws  java.util.regex.PatternSyntaxException
645      *              if the regular expression's syntax is invalid
646      *
647      * @see String#replaceFirst(String, String)
648      * @see java.util.regex.Pattern
649      * @see java.util.regex.Pattern#DOTALL
650      */
651     public static String replaceFirst(final String text, final String regex, final String replacement) {
652         if (text == null || regex == null || replacement == null) {
653             return text;
654         }
655         return text.replaceFirst(regex, replacement);
656     }
657 
658     /**
659      * Replaces each substring of the source String that matches the given regular expression with the given
660      * replacement using the {@link Pattern#DOTALL} option. DOTALL is also known as single-line mode in Perl.
661      *
662      * This call is a {@code null} safe equivalent to:
663      * <ul>
664      * <li>{@code text.replaceAll(&quot;(?s)&quot; + regex, replacement)}</li>
665      * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(text).replaceAll(replacement)}</li>
666      * </ul>
667      *
668      * <p>A {@code null} reference passed to this method is a no-op.</p>
669      *
670      * <pre>{@code
671      * StringUtils.replacePattern(null, *, *)       = null
672      * StringUtils.replacePattern("any", (String) null, *)   = "any"
673      * StringUtils.replacePattern("any", *, null)   = "any"
674      * StringUtils.replacePattern("", "", "zzz")    = "zzz"
675      * StringUtils.replacePattern("", ".*", "zzz")  = "zzz"
676      * StringUtils.replacePattern("", ".+", "zzz")  = ""
677      * StringUtils.replacePattern("<__>\n<__>", "<.*>", "z")       = "z"
678      * StringUtils.replacePattern("ABCabc123", "[a-z]", "_")       = "ABC___123"
679      * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "_")  = "ABC_123"
680      * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "")   = "ABC123"
681      * StringUtils.replacePattern("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
682      * }</pre>
683      *
684      * @param text
685      *            the source string
686      * @param regex
687      *            the regular expression to which this string is to be matched
688      * @param replacement
689      *            the string to be substituted for each match
690      * @return The resulting {@link String}
691      * @see #replaceAll(String, String, String)
692      * @see String#replaceAll(String, String)
693      * @see Pattern#DOTALL
694      * @since 3.18.0
695      */
696     public static String replacePattern(final CharSequence text, final String regex, final String replacement) {
697         if (ObjectUtils.anyNull(text, regex, replacement)) {
698             return toStringOrNull(text);
699         }
700         return dotAllMatcher(regex, text).replaceAll(replacement);
701     }
702 
703     /**
704      * Replaces each substring of the source String that matches the given regular expression with the given
705      * replacement using the {@link Pattern#DOTALL} option. DOTALL is also known as single-line mode in Perl.
706      *
707      * This call is a {@code null} safe equivalent to:
708      * <ul>
709      * <li>{@code text.replaceAll(&quot;(?s)&quot; + regex, replacement)}</li>
710      * <li>{@code Pattern.compile(regex, Pattern.DOTALL).matcher(text).replaceAll(replacement)}</li>
711      * </ul>
712      *
713      * <p>A {@code null} reference passed to this method is a no-op.</p>
714      *
715      * <pre>{@code
716      * StringUtils.replacePattern(null, *, *)       = null
717      * StringUtils.replacePattern("any", (String) null, *)   = "any"
718      * StringUtils.replacePattern("any", *, null)   = "any"
719      * StringUtils.replacePattern("", "", "zzz")    = "zzz"
720      * StringUtils.replacePattern("", ".*", "zzz")  = "zzz"
721      * StringUtils.replacePattern("", ".+", "zzz")  = ""
722      * StringUtils.replacePattern("<__>\n<__>", "<.*>", "z")       = "z"
723      * StringUtils.replacePattern("ABCabc123", "[a-z]", "_")       = "ABC___123"
724      * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "_")  = "ABC_123"
725      * StringUtils.replacePattern("ABCabc123", "[^A-Z0-9]+", "")   = "ABC123"
726      * StringUtils.replacePattern("Lorem ipsum  dolor   sit", "( +)([a-z]+)", "_$2")  = "Lorem_ipsum_dolor_sit"
727      * }</pre>
728      *
729      * @param text
730      *            the source string
731      * @param regex
732      *            the regular expression to which this string is to be matched
733      * @param replacement
734      *            the string to be substituted for each match
735      * @return The resulting {@link String}
736      * @see #replaceAll(String, String, String)
737      * @see String#replaceAll(String, String)
738      * @see Pattern#DOTALL
739      * @deprecated Use {@link #replacePattern(CharSequence, String, String)}.
740      */
741     @Deprecated
742     public static String replacePattern(final String text, final String regex, final String replacement) {
743         return replacePattern((CharSequence) text, regex, replacement);
744     }
745 
746     private static String toStringOrNull(final CharSequence text) {
747         return Objects.toString(text, null);
748     }
749 
750     /**
751      * Make private in 4.0.
752      *
753      * @deprecated TODO Make private in 4.0.
754      */
755     @Deprecated
756     public RegExUtils() {
757         // empty
758     }
759 }