
com.landawn.abacus.util.RegExUtil Maven / Gradle / Ivy
Show all versions of abacus-common Show documentation
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.landawn.abacus.util;
import java.util.function.Function;
import java.util.regex.MatchResult;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import com.landawn.abacus.annotation.Beta;
import com.landawn.abacus.util.function.IntBiFunction;
/**
* Note: Copied from Apache Commons Lang under Apache License V2.
*
*
*
* Helpers to process Strings using regular expressions.
* @see java.util.regex.Pattern
* @see java.util.regex.Matcher
* @see com.landawn.abacus.util.Strings
* @see Java Regular Expressions
* @see quickref
*/
public final class RegExUtil {
/**
* Pattern for a Java identifier.
*
* A Java identifier is a letter, currency character, or connecting punctuation character followed by
* zero or more Java letters, currency characters, connecting punctuation characters, digits,
* or one of the following special characters: {@code $} or {@code _}.
*
*/
public static final Pattern JAVA_IDENTIFIER_FINDER = Pattern.compile("([a-zA-Z_$][a-zA-Z\\d_$]*)");
/**
* A regular expression {@link Pattern} that matches integers within a string.
*
* This pattern captures sequences of digits that may optionally be prefixed
* with a plus or minus sign. It is useful for extracting signed or unsigned
* integer values from arbitrary text.
*
*
* Regex breakdown:
*
* - {@code [+-]?} — matches an optional '+' or '-' sign
* - {@code \\d+} — matches one or more digits
*
*
* Example matches:
*
* - {@code "42"}
* - {@code "-7"}
* - {@code "+1234"}
*
*
* @see java.util.regex.Pattern
*/
public static final Pattern INTEGER_FINDER = Pattern.compile("([+-]?\\d+)");
public static final Pattern POSITIVE_INTEGER_FINDER = Pattern.compile("\\d+");
public static final Pattern NEGATIVE_INTEGER_FINDER = Pattern.compile("-\\d+");
/**
* A regular expression {@link Pattern} that matches integer and decimal numbers in a string.
*
* This pattern captures numeric values that may include:
*
* - An optional leading '+' or '-' sign
* - An integer part (one or more digits)
* - An optional fractional part, starting with a dot and followed by one or more digits
*
* It can be used to extract signed or unsigned integers and floating-point numbers from text.
*
*
* Regex breakdown:
*
* - {@code [+-]?} — optional sign
* - {@code \\d+} — one or more digits (the integer part)
* - {@code (\\.\\d+)?} — optional decimal part (a dot followed by one or more digits)
*
*
* Example matches:
*
* - {@code "42"}
* - {@code "-3.14"}
* - {@code "+0.99"}
* - {@code "100."} (not matched)
* - {@code ".25"} (not matched)
*
*
* Note: This pattern does not match numbers like {@code .25} or {@code 100.}
* because a digit before the dot is required and the fractional part must have at least one digit after the dot.
*
* @see java.util.regex.Pattern
*/
public static final Pattern NUMBER_FINDER = Pattern.compile("([+-]?\\d+(\\.\\d+)?)");
public static final Pattern POSITIVE_NUMBER_FINDER = Pattern.compile("\\d*\\.?\\d+");
public static final Pattern NEGATIVE_NUMBER_FINDER = Pattern.compile("-\\d*\\.?\\d+");
/**
* A regular expression {@link Pattern} that matches numbers in standard or scientific notation.
*
* This pattern supports:
*
* - Optional leading '+' or '-' sign
* - An integer or decimal part (e.g., {@code 123}, {@code 3.14})
* - An optional exponent part with 'e' or 'E', followed by an optional sign and digits (e.g., {@code e+10}, {@code E-5})
*
* It can be used to extract integers, floating-point numbers, and scientific notation numbers from text.
*
*
* Regex breakdown:
*
* - {@code [+-]?} — optional sign
* - {@code \\d+} — one or more digits (integer part)
* - {@code (\\.\\d+)?} — optional decimal part
* - {@code ([eE][+-]?\\d+)?} — optional exponent part (e.g., {@code e10}, {@code E-3})
*
*
* Example matches:
*
* - {@code "42"}
* - {@code "-3.14"}
* - {@code "+6.022e23"}
* - {@code "1E-9"}
*
*
* Note: This pattern requires at least one digit before the decimal point,
* so values like {@code .5} are not matched. It also allows optional exponent notation, but only
* when preceded by a valid base number.
*
* @see java.util.regex.Pattern
*/
public static final Pattern SCIENTIFIC_NUMBER_FINDER = Pattern.compile("([+-]?\\d+(\\.\\d+)?([eE][+-]?\\d+)?)");
public static final Pattern PHONE_NUMBER_FINDER = Pattern.compile("\\+?[\\d\\s]{3,}");
public static final Pattern PHONE_NUMBER_WITH_CODE_FINDER = Pattern.compile("\\+?[\\d\\s]+\\(?[\\d\\s]{10,}");
/**
* Pattern for date in format yyyy-MM-dd or yyyy/MM/dd or yyyy.MM.dd or yyyy MM dd.
*
year is from 1900 to 2099.
*/
public static final Pattern DATE_FINDER = Pattern.compile("(19|20)\\d\\d([- /.])(0[1-9]|1[012])\\2(0[1-9]|[12][0-9]|3[01])");
/**
* Pattern for time in format HH:mm:ss.
*
hour is from 00 to 23, minute and second are from 00 to 59.
*/
public static final Pattern TIME_FINDER = Pattern.compile("([01]\\d|2[0-3]):([0-5]\\d):([0-5]\\d)");
/**
* Pattern for date and time in format yyyy-MM-dd HH:mm:ss or yyyy/MM/dd HH:mm:ss or yyyy.MM.dd HH:mm:ss or yyyy MM dd HH:mm:ss.
*
year is from 1900 to 2099, hour is from 00 to 23, minute and second are from 00 to 59.
*/
public static final Pattern DATE_TIME_FINDER = Pattern
.compile("(19|20)\\d\\d([- /.])(0[1-9]|1[012])\\2(0[1-9]|[12][0-9]|3[01]) ([01]\\d|2[0-3]):([0-5]\\d):([0-5]\\d)");
public static final Pattern BANK_CARD_NUMBER_FINDER = Pattern.compile("(?:\\d{4}[-\\s]?){3}\\d{4}");
// https://www.baeldung.com/java-email-validation-regex
// https://owasp.org/www-community/OWASP_Validation_Regex_Repository
// https://stackoverflow.com/questions/201323/how-can-i-validate-an-email-address-using-a-regular-expression
public static final Pattern EMAIL_ADDRESS_RFC_5322_FINDER = Pattern.compile(
"(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\])");
// https://stackoverflow.com/questions/3809401/what-is-a-good-regular-expression-to-match-a-url
public static final Pattern URL_FINDER = Pattern.compile("[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_\\+.~#?&//=]*)");
public static final Pattern HTTP_URL_FINDER = Pattern.compile("[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_\\+.~#?&//=]*)");
/**
* Pattern for alphanumeric string without space.
*/
public static final Pattern ALPHANUMERIC_FINDER = Pattern.compile("\\+?[\\d\\s]+\\(?[\\d\\s]{10,}");
/**
* Pattern for alphanumeric string with space.
*/
public static final Pattern ALPHANUMERIC_SPACE_FINDER = Pattern.compile("\\+?[\\d\\s]+\\(?[\\d\\s]{10,}");
/**
* Pattern for duplicate words.
*/
public static final Pattern DUPLICATES_FINDER = Pattern.compile("(\\b\\w+\\b)(?=.*\\b\\1\\b)");
/**
* Pattern for whitespace.
*/
public static final Pattern WHITESPACE_FINDER = Pattern.compile("\\s+");
// https://stackoverflow.com/questions/1449817/what-are-some-of-the-most-useful-regular-expressions-for-programmers
public static final Pattern JAVA_IDENTIFIER_MATCHER = Pattern.compile("^" + JAVA_IDENTIFIER_FINDER.pattern() + "$");
public static final Pattern INTEGER_MATCHER = Pattern.compile("^" + INTEGER_FINDER.pattern() + "$");
public static final Pattern POSITIVE_INTEGER_MATCHER = Pattern.compile("^" + POSITIVE_INTEGER_FINDER.pattern() + "$");
public static final Pattern NEGATIVE_INTEGER_MATCHER = Pattern.compile("^" + NEGATIVE_INTEGER_FINDER.pattern() + "$");
public static final Pattern NUMBER_MATCHER = Pattern.compile("^" + NUMBER_FINDER.pattern() + "$");
public static final Pattern POSITIVE_NUMBER_MATCHER = Pattern.compile("^" + POSITIVE_NUMBER_FINDER.pattern() + "$");
public static final Pattern NEGATIVE_NUMBER_MATCHER = Pattern.compile("^" + NEGATIVE_NUMBER_FINDER.pattern() + "$");
public static final Pattern SCIENTIFIC_NUMBER_MATCHER = Pattern.compile("^" + SCIENTIFIC_NUMBER_FINDER.pattern() + "$");
public static final Pattern PHONE_NUMBER_MATCHER = Pattern.compile("^" + PHONE_NUMBER_FINDER.pattern() + "$");
public static final Pattern PHONE_NUMBER_WITH_CODE_MATCHER = Pattern.compile("^" + PHONE_NUMBER_WITH_CODE_FINDER.pattern() + "$");
public static final Pattern DATE_MATCHER = Pattern.compile("^" + DATE_FINDER.pattern() + "$");
public static final Pattern TIME_MATCHER = Pattern.compile("^" + TIME_FINDER.pattern() + "$");
public static final Pattern DATE_TIME_MATCHER = Pattern.compile("^" + DATE_TIME_FINDER.pattern() + "$");
public static final Pattern BANK_CARD_NUMBER_MATCHER = Pattern.compile("^" + BANK_CARD_NUMBER_FINDER.pattern() + "$");
public static final Pattern EMAIL_ADDRESS_RFC_5322_MATCHER = Pattern.compile("^" + EMAIL_ADDRESS_RFC_5322_FINDER.pattern() + "$");
public static final Pattern URL_MATCHER = Pattern.compile("^" + URL_FINDER.pattern() + "$");
public static final Pattern HTTP_URL_MATCHER = Pattern.compile("^" + HTTP_URL_FINDER.pattern() + "$");
public static final Pattern ALPHANUMERIC_MATCHER = Pattern.compile("^" + ALPHANUMERIC_FINDER.pattern() + "$");
public static final Pattern ALPHANUMERIC_SPACE_MATCHER = Pattern.compile("^" + ALPHANUMERIC_SPACE_FINDER.pattern() + "$");
public static final Pattern DUPLICATES_MATCHER = Pattern.compile("^" + DUPLICATES_FINDER.pattern() + "$");
public static final Pattern WHITESPACE_MATCHER = Pattern.compile("^" + WHITESPACE_FINDER.pattern() + "$");
private RegExUtil() {
// Singleton for utility class.
}
/**
* Checks if the specified string contains a substring that matches the given regular expression.
*
* @param source the string to be checked, may be {@code null} or empty
* @param regex the regular expression to find
* @return {@code true} if the string contains a match, {@code false} otherwise
* @throws IllegalArgumentException if the {@code regex} is {@code null} or empty
* @see Pattern#find(CharSequence)
*/
public static boolean find(final String source, final String regex) throws IllegalArgumentException {
N.checkArgNotEmpty(regex, cs.regex);
return Pattern.compile(regex).matcher(source).find();
}
/**
* Checks if the specified string contains a substring that matches the given regular expression pattern.
*
* @param source the string to be checked, may be {@code null} or empty
* @param pattern the regular expression pattern to find
* @return {@code true} if the string contains a match, {@code false} otherwise
* @throws IllegalArgumentException if the pattern is {@code null}
* @see Pattern#find(CharSequence)
*/
public static boolean find(final String source, final Pattern pattern) throws IllegalArgumentException {
N.checkArgNotNull(pattern, cs.pattern);
return pattern.matcher(source).find();
}
/**
* Checks if the specified string matches the given regular expression.
*
* @param source the string to be checked, may be {@code null} or empty
* @param regex the regular expression to match
* @return {@code true} if the string matches the regex, {@code false} otherwise
* @throws IllegalArgumentException if the {@code regex} is {@code null} or empty
* @see Pattern#matches(String, CharSequence)
*/
public static boolean matches(final String source, final String regex) throws IllegalArgumentException {
N.checkArgNotEmpty(regex, cs.regex);
return Pattern.matches(regex, source);
}
/**
* Checks if the specified string matches the given regular expression pattern.
*
* @param source the string to be checked, may be {@code null} or empty
* @param pattern the regular expression pattern to match
* @return {@code true} if the string matches the regex, {@code false} otherwise
* @throws IllegalArgumentException if the pattern is {@code null}
* @see Pattern#matches(String, CharSequence)
*/
public static boolean matches(final String source, final Pattern pattern) throws IllegalArgumentException {
N.checkArgNotNull(pattern, cs.pattern);
return pattern.matcher(source).matches();
}
/**
* Removes each substring of the source string that matches the given regular expression.
*
* @param source source string to remove from, which may be null
* @param regex the regular expression to which this string is to be matched
* @return the source string with any removes processed, or an empty String {@code ""} if the input source string is {@code null}.
* @throws IllegalArgumentException if the {@code regex} is {@code null} or empty
* @see #replaceAll(String, String, String)
* @see String#replaceAll(String, String)
*/
public static String removeAll(final String source, final String regex) throws IllegalArgumentException {
return replaceAll(source, regex, Strings.EMPTY);
}
/**
* Removes each substring of the source string that matches the given regular expression pattern.
*
* @param source source string to remove from, which may be null
* @param pattern the regular expression to which this string is to be matched
* @return the source string with any removes processed, or an empty String {@code ""} if the input source string is {@code null}.
* @throws IllegalArgumentException if the pattern is {@code null}
* @see #replaceAll(String, Pattern, String)
* @see java.util.regex.Matcher#replaceAll(String)
*/
public static String removeAll(final String source, final Pattern pattern) throws IllegalArgumentException {
return replaceAll(source, pattern, Strings.EMPTY);
}
/**
* Removes the first substring of the source string that matches the given regular expression.
*
* @param source source string to remove from, which may be null
* @param regex the regular expression to which this string is to be matched
* @return the source string with the first replacement processed, or an empty String {@code ""} if the input source string is {@code null}.
* @throws IllegalArgumentException if the {@code regex} is {@code null} or empty
* @see #replaceFirst(String, String, String)
* @see String#replaceFirst(String, String)
* @see java.util.regex.Pattern
*/
public static String removeFirst(final String source, final String regex) throws IllegalArgumentException {
return replaceFirst(source, regex, Strings.EMPTY);
}
/**
* Removes the first substring of the source string that matches the given regular expression pattern.
*
* @param source source string to remove from, which may be null
* @param pattern the regular expression pattern to which this string is to be matched
* @return the source string with the first replacement processed, or an empty String {@code ""} if the input source string is {@code null}.
* @throws IllegalArgumentException if the pattern is {@code null}
* @see #replaceFirst(String, Pattern, String)
* @see java.util.regex.Matcher#replaceFirst(String)
* @see java.util.regex.Pattern
*/
public static String removeFirst(final String source, final Pattern pattern) throws IllegalArgumentException {
return replaceFirst(source, pattern, Strings.EMPTY);
}
/**
* Removes the last substring of the source string that matches the given regular expression.
*
* @param source source string to remove from, which may be null
* @param regex the regular expression to which this string is to be matched
* @return the source string with the last replacement processed, or an empty String {@code ""} if the input source string is {@code null}.
* @throws IllegalArgumentException if the {@code regex} is {@code null} or empty
* @see #replaceFirst(String, String, String)
* @see java.util.regex.Pattern
*/
@Beta
public static String removeLast(final String source, final String regex) throws IllegalArgumentException {
return replaceLast(source, regex, Strings.EMPTY);
}
/**
* Removes the last substring of the source string that matches the given regular expression pattern.
*
* @param source source string to remove from, which may be null
* @param pattern the regular expression pattern to which this string is to be matched
* @return the source string with the last replacement processed, or an empty String {@code ""} if the input source string is {@code null}.
* @throws IllegalArgumentException if the pattern is {@code null}
* @see #replaceLast(String, Pattern, String)
* @see java.util.regex.Pattern
*/
@Beta
public static String removeLast(final String source, final Pattern pattern) throws IllegalArgumentException {
return replaceLast(source, pattern, Strings.EMPTY);
}
/**
* Replaces each substring of the source string that matches the given regular expression
* with the given replacement.
*
* This method is a {@code null} safe equivalent to:
*
* - {@code source.replaceAll(regex, replacement)}
* - {@code Pattern.compile(regex).matcher(source).replaceAll(replacement)}
*
*
*
* @param source source string to search and replace in, which may be null
* @param regex the regular expression to which this string is to be matched
* @param replacement the string to be substituted for each match
* @return the source string with any replacements processed, or an empty String {@code ""} if the input source string is {@code null}.
* @throws IllegalArgumentException if the {@code regex} is {@code null} or empty
* @see String#replaceAll(String, String)
*/
public static String replaceAll(final String source, final String regex, final String replacement) throws IllegalArgumentException {
N.checkArgNotEmpty(regex, cs.regex);
return replaceAll(source, Pattern.compile(regex), Strings.nullToEmpty(replacement));
}
/**
* Replaces each substring of the source string that matches the given regular expression
* with the given replacement.
*
* This method is a {@code null} safe equivalent to:
*
* - {@code source.replaceAll(regex, replacement)}
* - {@code Pattern.compile(regex).matcher(source).replaceAll(replacer)}
*
*
*
* @param source source string to search and replace in, which may be null
* @param regex the regular expression to which this string is to be matched
* @param replacer The function to be applied to the match result of this matcher that returns a replacement string.
* @return the source string with any replacements processed, or an empty String {@code ""} if the input source string is {@code null}.
* @throws IllegalArgumentException if the {@code regex} is {@code null} or empty
* @see String#replaceAll(String, String)
*/
public static String replaceAll(final String source, final String regex, final Function replacer) throws IllegalArgumentException {
N.checkArgNotEmpty(regex, cs.regex);
return replaceAll(source, Pattern.compile(regex), replacer);
}
/**
* Replaces each substring of the source string that matches the given regular expression
* with the given replacement.
*
* This method is a {@code null} safe equivalent to:
*
* - {@code source.replaceAll(regex, replacement)}
* - {@code Pattern.compile(regex).matcher(source).replaceAll(replacer)}
*
*
*
* @param source source string to search and replace in, which may be null
* @param regex the regular expression to which this string is to be matched
* @param replacer The function to be applied to the match result of this matcher that returns a replacement string.
* @return the source string with any replacements processed, or an empty String {@code ""} if the input source string is {@code null}.
* @throws IllegalArgumentException if the {@code regex} is {@code null} or empty
* @see String#replaceAll(String, String)
*/
public static String replaceAll(final String source, final String regex, final IntBiFunction replacer) throws IllegalArgumentException {
N.checkArgNotEmpty(regex, cs.regex);
return replaceAll(source, Pattern.compile(regex), replacer);
}
/**
* Replaces each substring of the source string that matches the given regular expression pattern with the given replacement.
*
* This method is a {@code null} safe equivalent to:
*
* - {@code pattern.matcher(source).replaceAll(replacement)}
*
*
*
* @param source source string to search and replace in, which may be null
* @param pattern the regular expression pattern to which this string is to be matched
* @param replacement the string to be substituted for each match
* @return the source string with any replacements processed, or an empty String {@code ""} if the input source string is {@code null}.
* @throws IllegalArgumentException if the pattern is {@code null}
* @see java.util.regex.Matcher#replaceAll(String)
* @see java.util.regex.Pattern
*/
public static String replaceAll(final String source, final Pattern pattern, final String replacement) throws IllegalArgumentException {
N.checkArgNotNull(pattern, cs.pattern);
if (Strings.isEmpty(source)) {
return Strings.EMPTY;
}
return pattern.matcher(source).replaceAll(Strings.nullToEmpty(replacement));
}
/**
* Replaces each substring of the source string that matches the given regular expression
* with the given replacement.
*
* This method is a {@code null} safe equivalent to:
*
* - {@code Pattern.compile(regex).matcher(source).replaceAll(replacer)}
*
*
*
* @param source source string to search and replace in, which may be null
* @param pattern the regular expression to which this string is to be matched
* @param replacer The function to be applied to the match result of this matcher that returns a replacement string.
* @return the source string with any replacements processed, or an empty String {@code ""} if the input source string is {@code null}.
* @throws IllegalArgumentException if the pattern is {@code null}
* @see String#replaceAll(String, String)
*/
public static String replaceAll(final String source, final Pattern pattern, final Function replacer) throws IllegalArgumentException {
N.checkArgNotNull(pattern, cs.pattern);
if (Strings.isEmpty(source)) {
return Strings.EMPTY;
}
return pattern.matcher(source).replaceAll(matcher -> replacer.apply(source.substring(matcher.start(), matcher.end())));
}
/**
* Replaces each substring of the source string that matches the given regular expression
* with the given replacement.
*
* This method is a {@code null} safe equivalent to:
*
* - {@code Pattern.compile(regex).matcher(source).replaceAll(replacer)}
*
*
*
* @param source source string to search and replace in, which may be null
* @param pattern the regular expression to which this string is to be matched
* @param replacer The function to be applied to the match result of this matcher that returns a replacement string.
* @return the source string with any replacements processed, or an empty String {@code ""} if the input source string is {@code null}.
* @throws IllegalArgumentException if the pattern is {@code null}
* @see String#replaceAll(String, String)
*/
public static String replaceAll(final String source, final Pattern pattern, final IntBiFunction replacer) throws IllegalArgumentException {
N.checkArgNotNull(pattern, cs.pattern);
if (Strings.isEmpty(source)) {
return Strings.EMPTY;
}
return pattern.matcher(source).replaceAll(matcher -> replacer.apply(matcher.start(), matcher.end()));
}
/**
* Replaces the first substring of the source string that matches the given regular expression with the given replacement.
*
* @param source source string to search and replace in, which may be null
* @param regex the regular expression to which this string is to be matched
* @param replacement the string to be substituted for the first match
* @return the source string with the first replacement processed, or an empty String {@code ""} if the input source string is {@code null}.
* @throws IllegalArgumentException if the {@code regex} is {@code null} or empty
* @see String#replaceFirst(String, String)
*/
public static String replaceFirst(final String source, final String regex, final String replacement) throws IllegalArgumentException {
N.checkArgNotEmpty(regex, cs.regex);
if (Strings.isEmpty(source)) {
return Strings.EMPTY;
}
return replaceFirst(source, Pattern.compile(regex), N.nullToEmpty(replacement));
}
/**
* Replaces the first substring of the source string that matches the given regular expression with the given replacement.
*
* @param source source string to search and replace in, which may be null
* @param regex the regular expression to which this string is to be matched
* @param replacer The function to be applied to the match result of this matcher that returns a replacement string.
* @return the source string with the first replacement processed, or an empty String {@code ""} if the input source string is {@code null}.
* @throws IllegalArgumentException if the {@code regex} is {@code null} or empty
* @see String#replaceFirst(String, String)
*/
public static String replaceFirst(final String source, final String regex, final Function replacer) throws IllegalArgumentException {
N.checkArgNotEmpty(regex, cs.regex);
return replaceFirst(source, Pattern.compile(regex), replacer);
}
/**
* Replaces the first substring of the source string that matches the given regular expression with the given replacement.
*
* @param source source string to search and replace in, which may be null
* @param regex the regular expression to which this string is to be matched
* @param replacer The function to be applied to the match result of this matcher that returns a replacement string.
* @return the source string with the first replacement processed, or an empty String {@code ""} if the input source string is {@code null}.
* @throws IllegalArgumentException if the {@code regex} is {@code null} or empty
* @see String#replaceFirst(String, String)
*/
public static String replaceFirst(final String source, final String regex, final IntBiFunction replacer) throws IllegalArgumentException {
N.checkArgNotEmpty(regex, cs.regex);
return replaceFirst(source, Pattern.compile(regex), replacer);
}
/**
* Replaces the first substring of the source string that matches the given regular expression pattern with the given replacement.
*
* This method is a {@code null} safe equivalent to:
*
* - {@code pattern.matcher(source).replaceFirst(replacement)}
*
*
*
* @param source source string to search and replace in, which may be null
* @param pattern the regular expression pattern to which this string is to be matched
* @param replacement the string to be substituted for the first match
* @return the source string with the first replacement processed, or an empty String {@code ""} if the input source string is {@code null}.
* @throws IllegalArgumentException if the pattern is {@code null}
* @see java.util.regex.Matcher#replaceFirst(String)
*/
public static String replaceFirst(final String source, final Pattern pattern, final String replacement) throws IllegalArgumentException {
N.checkArgNotNull(pattern, cs.pattern);
if (Strings.isEmpty(source)) {
return Strings.EMPTY;
}
return pattern.matcher(source).replaceFirst(Strings.nullToEmpty(replacement));
}
/**
* Replaces the first substring of the source string that matches the given regular expression pattern with the given replacer.
*
* This method is a {@code null} safe equivalent to:
*
* - {@code pattern.matcher(source).replaceFirst(replacer)}
*
*
*
* @param source source string to search and replace in, which may be null
* @param pattern the regular expression pattern to which this string is to be matched
* @param replacer The function to be applied to the match result of this matcher that returns a replacement string.
* @return the source string with the first replacement processed, or an empty String {@code ""} if the input source string is {@code null}.
* @throws IllegalArgumentException if the pattern is {@code null}
* @see java.util.regex.Matcher#replaceFirst(String)
*/
public static String replaceFirst(final String source, final Pattern pattern, final Function replacer) throws IllegalArgumentException {
N.checkArgNotNull(pattern, cs.pattern);
if (Strings.isEmpty(source)) {
return Strings.EMPTY;
}
return pattern.matcher(source).replaceFirst(matcher -> replacer.apply(source.substring(matcher.start(), matcher.end())));
}
/**
* Replaces the first substring of the source string that matches the given regular expression pattern with the given replacer.
*
* This method is a {@code null} safe equivalent to:
*
* - {@code pattern.matcher(source).replaceFirst(replacer)}
*
*
*
* @param source source string to search and replace in, which may be null
* @param pattern the regular expression pattern to which this string is to be matched
* @param replacer The function to be applied to the match result of this matcher that returns a replacement string.
* @return the source string with the first replacement processed, or an empty String {@code ""} if the input source string is {@code null}.
* @throws IllegalArgumentException if the pattern is {@code null}
* @see java.util.regex.Matcher#replaceFirst(String)
*/
public static String replaceFirst(final String source, final Pattern pattern, final IntBiFunction replacer) throws IllegalArgumentException {
N.checkArgNotNull(pattern, cs.pattern);
if (Strings.isEmpty(source)) {
return Strings.EMPTY;
}
return pattern.matcher(source).replaceFirst(matcher -> replacer.apply(matcher.start(), matcher.end()));
}
/**
* Searches the last occurrence of the specified {@code regex} pattern in the specified source string, and replace it with the specified {@code replacement}.
*
* @param source
* @param regex
* @param replacement
* @return the source string with the last replacement processed, or an empty String {@code ""} if the input source string is {@code null}.
* @throws IllegalArgumentException if the {@code regex} is {@code null} or empty
* @see Matcher#replaceFirst(String)
*/
@Beta
public static String replaceLast(final String source, final String regex, final String replacement) throws IllegalArgumentException {
N.checkArgNotEmpty(regex, cs.regex);
return replaceLast(source, Pattern.compile(regex), replacement);
}
/**
* Searches the last occurrence of the specified {@code regex} pattern in the specified source string, and replace it with the specified {@code replacer}.
*
* @param source
* @param regex
* @param replacer The function to be applied to the match result of this matcher that returns a replacement string.
* @return the source string with the last replacement processed, or an empty String {@code ""} if the input source string is {@code null}.
* @throws IllegalArgumentException if the {@code regex} is {@code null} or empty
* @see Matcher#replaceFirst(Function)
*/
@Beta
public static String replaceLast(final String source, final String regex, final Function replacer) throws IllegalArgumentException {
N.checkArgNotEmpty(regex, cs.regex);
return replaceLast(source, Pattern.compile(regex), replacer);
}
/**
* Searches the last occurrence of the specified {@code regex} pattern in the specified source string, and replace it with the specified {@code replacer}.
*
* @param source
* @param regex
* @param replacer The function to be applied to the match result of this matcher that returns a replacement string.
* @return the source string with the last replacement processed, or an empty String {@code ""} if the input source string is {@code null}.
* @throws IllegalArgumentException if the {@code regex} is {@code null} or empty
* @see Matcher#replaceFirst(Function)
*/
@Beta
public static String replaceLast(final String source, final String regex, final IntBiFunction replacer) throws IllegalArgumentException {
N.checkArgNotEmpty(regex, cs.regex);
if (Strings.isEmpty(source)) {
return Strings.EMPTY;
}
return replaceLast(source, Pattern.compile(regex), replacer);
}
/**
* Searches the last occurrence of the specified {@code regex} pattern in the specified source string, and replace it with the specified {@code replacement}.
*
* @param source
* @param pattern
* @param replacement
* @return the source string with the last replacement processed, or an empty String {@code ""} if the input source string is {@code null}.
* @throws IllegalArgumentException if the pattern is {@code null}
* @see Matcher#replaceFirst(String)
*/
@Beta
public static String replaceLast(final String source, final Pattern pattern, final String replacement) throws IllegalArgumentException {
N.checkArgNotNull(pattern, cs.pattern);
if (Strings.isEmpty(source)) {
return Strings.EMPTY;
}
final Matcher matcher = pattern.matcher(source);
for (int start = -1, end = -1, i = source.length(); i >= 0; i--) {
if (matcher.find(i)) {
if (start < 0 || (matcher.start() < start && matcher.end() >= end)) {
start = matcher.start();
end = matcher.end();
} else {
return Strings.replaceRange(source, start, end, replacement);
}
} else if (start >= 0) {
return Strings.replaceRange(source, start, end, replacement);
}
}
return source;
}
/**
* Searches the last occurrence of the specified {@code regex} pattern in the specified source string, and replace it with the specified {@code replacer}.
*
* @param source
* @param pattern
* @param replacer The function to be applied to the match result of this matcher that returns a replacement string.
* @return the source string with the last replacement processed, or an empty String {@code ""} if the input source string is {@code null}.
* @throws IllegalArgumentException if the pattern is {@code null}
* @see Matcher#replaceFirst(Function)
*/
@Beta
public static String replaceLast(final String source, final Pattern pattern, final Function replacer) throws IllegalArgumentException {
N.checkArgNotNull(pattern, cs.pattern);
if (Strings.isEmpty(source)) {
return Strings.EMPTY;
}
final Matcher matcher = pattern.matcher(source);
for (int start = -1, end = -1, i = source.length(); i >= 0; i--) {
if (matcher.find(i)) {
if (start < 0 || (matcher.start() < start && matcher.end() >= end)) {
start = matcher.start();
end = matcher.end();
} else {
return Strings.replaceRange(source, start, end, replacer.apply(source.substring(matcher.start(), matcher.end())));
}
} else if (start >= 0) {
return Strings.replaceRange(source, start, end, replacer.apply(source.substring(matcher.start(), matcher.end())));
}
}
return source;
}
/**
* Searches the last occurrence of the specified {@code regex} pattern in the specified source string, and replace it with the specified {@code replacer}.
*
* @param source
* @param pattern
* @param replacer The function to be applied to the match result of this matcher that returns a replacement string.
* @return the source string with the last replacement processed, or an empty String {@code ""} if the input source string is {@code null}.
* @throws IllegalArgumentException if the pattern is {@code null}
* @see Matcher#replaceFirst(Function)
*/
@Beta
public static String replaceLast(final String source, final Pattern pattern, final IntBiFunction replacer) throws IllegalArgumentException {
N.checkArgNotNull(pattern, cs.pattern);
if (Strings.isEmpty(source)) {
return Strings.EMPTY;
}
final Matcher matcher = pattern.matcher(source);
for (int start = -1, end = -1, i = source.length(); i >= 0; i--) {
if (matcher.find(i)) {
if (start < 0 || (matcher.start() < start && matcher.end() >= end)) {
start = matcher.start();
end = matcher.end();
} else {
return Strings.replaceRange(source, start, end, replacer.apply(matcher.start(), matcher.end()));
}
} else if (start >= 0) {
return Strings.replaceRange(source, start, end, replacer.apply(matcher.start(), matcher.end()));
}
}
return source;
}
/**
* Counts the number of occurrences of the specified pattern in the given string.
*
* @param source the string to be checked, may be {@code null} or empty
* @param regex the regular expression pattern to be counted
* @return the number of occurrences of the specified pattern in the string, or 0 if the input source string is {@code null} or empty
* @see #countMatches(String, String)
*/
public static int countMatches(final String source, final String regex) throws IllegalArgumentException {
N.checkArgNotEmpty(regex, cs.regex);
if (Strings.isEmpty(source)) {
return 0;
}
return countMatches(source, Pattern.compile(regex));
}
/**
* Counts the number of occurrences of the specified pattern in the given string.
*
* @param source the string to be checked, may be {@code null} or empty
* @param pattern the regular expression pattern to be counted
* @return the number of occurrences of the specified pattern in the string, or 0 if the input source string is {@code null} or empty
* @throws IllegalArgumentException if the pattern is {@code null}
* @see #countMatches(String, String)
*/
public static int countMatches(final String source, final Pattern pattern) throws IllegalArgumentException {
N.checkArgNotNull(pattern, cs.pattern);
if (Strings.isEmpty(source)) {
return 0;
}
final Matcher matcher = pattern.matcher(source);
int occurrences = 0;
while (matcher.find()) {
occurrences++;
}
return occurrences;
}
/**
* Finds all the occurrences of the specified pattern in the given string.
*
* @param source the string to be checked, may be {@code null} or empty
* @param regex the regular expression pattern to be counted
* @return a stream of match results for each subsequence of the input sequence that matches the pattern.
* @throws IllegalArgumentException if the {@code regex} is {@code null} or empty
* @see Matcher#results()
*/
public static Stream matchResults(final String source, final String regex) throws IllegalArgumentException {
N.checkArgNotEmpty(regex, cs.regex);
if (Strings.isEmpty(source)) {
return Stream.empty();
}
return matchResults(source, Pattern.compile(regex));
}
/**
* Finds all the occurrences of the specified pattern in the given string.
*
* @param source the string to be checked, may be {@code null} or empty
* @param pattern the regular expression pattern to be counted
* @return a stream of match results for each subsequence of the input sequence that matches the pattern.
* @throws IllegalArgumentException if the pattern is {@code null}
* @see Matcher#results()
*/
public static Stream matchResults(final String source, final Pattern pattern) throws IllegalArgumentException {
N.checkArgNotNull(pattern, cs.pattern);
if (Strings.isEmpty(source)) {
return Stream.empty();
}
return pattern.matcher(source).results();
}
/**
* Finds all the occurrences of the specified pattern in the given string and returns a stream of start indices.
*
* @param source the string to be checked, may be {@code null} or empty
* @param regex the regular expression pattern to be counted
* @return a stream of start indices for each subsequence of the input sequence that matches the pattern
* @throws IllegalArgumentException if the {@code regex} is {@code null} or empty
* @see Matcher#results()
* @see Strings#indicesOf(String, String)
* @see Strings#indicesOf(String, String, int)
*/
public static IntStream matchIndices(final String source, final String regex) throws IllegalArgumentException {
N.checkArgNotEmpty(regex, cs.regex);
if (Strings.isEmpty(source)) {
return IntStream.empty();
}
return matchIndices(source, Pattern.compile(regex));
}
/**
* Finds all the occurrences of the specified pattern in the given string and returns a stream of start indices.
*
* @param source the string to be checked, may be {@code null} or empty
* @param pattern the regular expression pattern to be counted
* @return a stream of start indices for each subsequence of the input sequence that matches the pattern
* @throws IllegalArgumentException if the pattern is {@code null}
* @see Matcher#results()
* @see Strings#indicesOf(String, String)
* @see Strings#indicesOf(String, String, int)
*/
public static IntStream matchIndices(final String source, final Pattern pattern) throws IllegalArgumentException {
N.checkArgNotNull(pattern, cs.pattern);
if (Strings.isEmpty(source)) {
return IntStream.empty();
}
return pattern.matcher(source).results().mapToInt(MatchResult::start);
}
/**
* Splits the given string into an array of strings based on the specified regular expression.
* If the string is {@code null}, an empty array is returned. If the string is empty, an array containing an empty string is returned.
*
* @param source the string to be split, may be {@code null} or empty
* @param regex the regular expression to split by
* @return an array of strings computed by splitting the source string around matches of the given regular expression
* @throws IllegalArgumentException if the {@code regex} is {@code null} or empty
* @see String#split(String)
* @see Pattern#split(String)
* @see Splitter#with(Pattern)
* @see Splitter#split(String)
*/
public static String[] split(final String source, final String regex) throws IllegalArgumentException {
N.checkArgNotEmpty(regex, cs.regex);
if (source == null) {
return N.EMPTY_STRING_ARRAY;
} else if (source.isEmpty()) {
return new String[] { Strings.EMPTY };
}
return source.split(regex);
}
/**
* Splits the given string into an array of strings based on the specified regular expression with a limit.
* If the string is {@code null}, an empty array is returned. If the string is empty, an array containing an empty string is returned.
*
* @param source the string to be split, may be {@code null} or empty
* @param regex the regular expression to split by
* @param limit the result threshold. A non-positive limit indicates no limit.
* @return an array of strings computed by splitting the source string around matches of the given regular expression
* @throws IllegalArgumentException if the {@code regex} is {@code null} or empty
* @see String#split(String, int)
* @see Pattern#split(String, int)
* @see Splitter#with(Pattern)
* @see Splitter#split(String)
*/
public static String[] split(final String source, final String regex, final int limit) throws IllegalArgumentException {
N.checkArgNotEmpty(regex, cs.regex);
if (source == null) {
return N.EMPTY_STRING_ARRAY;
} else if (source.isEmpty()) {
return new String[] { Strings.EMPTY };
}
return source.split(regex, limit);
}
/**
* Splits the given string into an array of strings based on the specified regular expression pattern.
* If the string is {@code null}, an empty array is returned. If the string is empty, an array containing an empty string is returned.
*
* @param source the string to be split, may be {@code null} or empty
* @param pattern the regular expression pattern to split by
* @return an array of strings computed by splitting the source string around matches of the given regular expression
* @throws IllegalArgumentException if the pattern is {@code null}
* @see String#split(String)
* @see Pattern#split(String)
* @see Splitter#with(Pattern)
* @see Splitter#split(String)
*/
public static String[] split(final String source, final Pattern pattern) throws IllegalArgumentException {
N.checkArgNotNull(pattern, cs.pattern);
if (source == null) {
return N.EMPTY_STRING_ARRAY;
} else if (source.isEmpty()) {
return new String[] { Strings.EMPTY };
}
return pattern.split(source);
}
/**
* Splits the given string into an array of strings based on the specified regular expression pattern with a limit.
* If the string is {@code null}, an empty array is returned. If the string is empty, an array containing an empty string is returned.
*
* @param source the string to be split, may be {@code null} or empty
* @param pattern the regular expression pattern to split by
* @param limit the result threshold. A non-positive limit indicates no limit.
* @return an array of strings computed by splitting the source string around matches of the given regular expression
* @throws IllegalArgumentException if the pattern is {@code null}
* @see String#split(String, int)
* @see Pattern#split(String, int)
* @see Splitter#with(Pattern)
* @see Splitter#split(String)
*/
public static String[] split(final String source, final Pattern pattern, final int limit) throws IllegalArgumentException {
N.checkArgNotNull(pattern, cs.pattern);
if (source == null) {
return N.EMPTY_STRING_ARRAY;
} else if (source.isEmpty()) {
return new String[] { Strings.EMPTY };
}
return pattern.split(source, limit);
}
}