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