001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      https://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.lang3;
018
019import java.util.Objects;
020import java.util.regex.Matcher;
021import java.util.regex.Pattern;
022
023/**
024 * Helpers to process Strings using regular expressions.
025 *
026 * @see java.util.regex.Pattern
027 * @since 3.8
028 */
029public class RegExUtils {
030
031    /**
032     * Compiles the given regular expression into a pattern with the {@link Pattern#DOTALL} flag.
033     *
034     * @param regex The expression to be compiled
035     * @return the given regular expression compiled into a pattern with the {@link Pattern#DOTALL} flag.
036     * @since 3.13.0
037     */
038    public static Pattern dotAll(final String regex) {
039        return Pattern.compile(regex, Pattern.DOTALL);
040    }
041
042    /**
043     * 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
044     * this pattern.
045     *
046     * @param regex The expression to be compiled.
047     * @param text  The character sequence to be matched.
048     * @return A new matcher for this pattern.
049     * @since 3.18.0
050     */
051    public static Matcher dotAllMatcher(final String regex, final CharSequence text) {
052        return dotAll(regex).matcher(text);
053    }
054
055    /**
056     * 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
057     * this pattern.
058     *
059     * @param regex The expression to be compiled.
060     * @param text  The character sequence to be matched.
061     * @return A new matcher for this pattern.
062     * @since 3.13.0
063     * @deprecated Use {@link #dotAllMatcher(String, CharSequence)}.
064     */
065    @Deprecated
066    public static Matcher dotAllMatcher(final String regex, final String text) {
067        return dotAll(regex).matcher(text);
068    }
069
070    /**
071     * Removes each substring of the text String that matches the given regular expression pattern.
072     *
073     * This method is a {@code null} safe equivalent to:
074     * <ul>
075     *  <li>{@code pattern.matcher(text).replaceAll(StringUtils.EMPTY)}</li>
076     * </ul>
077     *
078     * <p>A {@code null} reference passed to this method is a no-op.</p>
079     *
080     * <pre>{@code
081     * StringUtils.removeAll(null, *)      = null
082     * StringUtils.removeAll("any", (Pattern) null)  = "any"
083     * StringUtils.removeAll("any", Pattern.compile(""))    = "any"
084     * StringUtils.removeAll("any", Pattern.compile(".*"))  = ""
085     * StringUtils.removeAll("any", Pattern.compile(".+"))  = ""
086     * StringUtils.removeAll("abc", Pattern.compile(".?"))  = ""
087     * StringUtils.removeAll("A<__>\n<__>B", Pattern.compile("<.*>"))      = "A\nB"
088     * StringUtils.removeAll("A<__>\n<__>B", Pattern.compile("(?s)<.*>"))  = "AB"
089     * StringUtils.removeAll("A<__>\n<__>B", Pattern.compile("<.*>", Pattern.DOTALL))  = "AB"
090     * StringUtils.removeAll("ABCabc123abc", Pattern.compile("[a-z]"))     = "ABC123"
091     * }</pre>
092     *
093     * @param text  text to remove from, may be null
094     * @param regex  the regular expression to which this string is to be matched
095     * @return  the text with any removes processed,
096     *              {@code null} if null String input
097     *
098     * @see #replaceAll(CharSequence, Pattern, String)
099     * @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}