    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}