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