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