diff --git a/src/main/java/xyz/zhouxy/plusone/commons/util/RegexUtil.java b/src/main/java/xyz/zhouxy/plusone/commons/util/RegexUtil.java index 3db7630..abd7d82 100644 --- a/src/main/java/xyz/zhouxy/plusone/commons/util/RegexUtil.java +++ b/src/main/java/xyz/zhouxy/plusone/commons/util/RegexUtil.java @@ -16,42 +16,132 @@ package xyz.zhouxy.plusone.commons.util; -import javax.annotation.Nullable; - -import xyz.zhouxy.plusone.commons.collection.SafeConcurrentHashMap; - -import java.util.Map; -import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import java.util.regex.Matcher; import java.util.regex.Pattern; -public class RegexUtil { +import javax.annotation.Nullable; - private static final Map PATTERN_CACHE = new SafeConcurrentHashMap<>(); +import com.google.common.base.Preconditions; - public static Pattern getPattern(final String regex) { - Objects.requireNonNull(regex); - return PATTERN_CACHE.computeIfAbsent(regex, Pattern::compile); +/** + * 封装一些常用的正则操作,并可以缓存 {@link Pattern} 实例以复用(最多缓存 256 个)。 + * + * @author ZhouXY + * + */ +public final class RegexUtil { + + private static final int DEFAULT_CACHE_INITIAL_CAPACITY = 64; + private static final int MAX_CACHE_SIZE = 256; + private static final ConcurrentHashMap PATTERN_CACHE = new ConcurrentHashMap<>( + DEFAULT_CACHE_INITIAL_CAPACITY); + + /** + * 获取 {@link Pattern} 实例。 + * + * @param pattern 正则表达式 + * @param cachePattern 是否缓存 {@link Pattern} 实例 + * @return {@link Pattern} 实例 + */ + public static Pattern getPattern(final String pattern, final boolean cachePattern) { + Preconditions.checkNotNull(pattern, "The pattern can not be null."); + Pattern result = PATTERN_CACHE.get(pattern); + if (result == null) { + result = Pattern.compile(pattern); + if (cachePattern && PATTERN_CACHE.size() < MAX_CACHE_SIZE) { + PATTERN_CACHE.putIfAbsent(pattern, result); + result = PATTERN_CACHE.get(pattern); + } + } + return result; } - public static boolean matches(@Nullable CharSequence input, String regex) { - return matches(input, getPattern(regex)); + /** + * 获取 {@link Pattern} 实例,不缓存。 + * + * @param pattern 正则表达式 + * @return {@link Pattern} 实例 + */ + public static Pattern getPattern(final String pattern) { + Preconditions.checkNotNull(pattern, "The pattern can not be null."); + Pattern result = PATTERN_CACHE.get(pattern); + if (result == null) { + result = Pattern.compile(pattern); + } + return result; } - public static boolean matches(@Nullable CharSequence input, Pattern pattern) { - Assert.notNull(pattern, "Pattern must not be null."); + /** + * 将各个正则表达式转为 {@link Pattern} 实例。 + * + * @param patterns 正则表达式 + * @param cachePattern 是否缓存 {@link Pattern} 实例 + * @return Pattern 实例数组 + */ + public static Pattern[] getPatterns(final String[] patterns, final boolean cachePattern) { + Preconditions.checkNotNull(patterns, "The patterns can not be null."); + final Pattern[] result = new Pattern[patterns.length]; + for (int i = 0; i < patterns.length; i++) { + result[i] = getPattern(patterns[i], cachePattern); + } + return result; + } + + /** + * 将各个正则表达式转为 {@link Pattern} 实例,不缓存。 + * + * @param patterns 正则表达式 + * @return {@link Pattern} 实例数组 + */ + public static Pattern[] getPatterns(final String[] patterns) { + Preconditions.checkNotNull(patterns, "The patterns can not be null."); + final Pattern[] result = new Pattern[patterns.length]; + for (int i = 0; i < patterns.length; i++) { + result[i] = getPattern(patterns[i]); + } + return result; + } + + /** + * 手动缓存 Pattern 实例。 + * + * @param pattern 要缓存的 {@link Pattern} 实例 + * @return 缓存的 Pattern 实例。如果缓存已满,则返回 {@code null}。 + */ + public static Pattern cachePattern(final Pattern pattern) { + if (PATTERN_CACHE.size() >= MAX_CACHE_SIZE) { + return null; + } + final String patternStr = pattern.pattern(); + PATTERN_CACHE.putIfAbsent(patternStr, pattern); + return PATTERN_CACHE.get(patternStr); + } + + /** + * 判断 {@code input} 是否匹配 {@code pattern}。 + * + * @param input 输入 + * @param pattern 正则 + * @return 判断结果 + */ + public static boolean matches(@Nullable final CharSequence input, final Pattern pattern) { + Preconditions.checkNotNull(pattern, "The pattern can not be null."); return input != null && pattern.matcher(input).matches(); } - public static boolean matchesOr(@Nullable CharSequence input, String... regexes) { - for (String regex : regexes) { - if (matches(input, regex)) { - return true; - } + /** + * 判断 {@code input} 是否匹配 {@code patterns} 中的一个。 + * + * @param input 输入 + * @param patterns 正则 + * @return 判断结果 + */ + public static boolean matchOne(@Nullable final CharSequence input, final Pattern[] patterns) { + Preconditions.checkNotNull(patterns, "The patterns can not be null."); + if (input == null) { + return false; } - return false; - } - - public static boolean matchesOr(@Nullable CharSequence input, Pattern... patterns) { for (Pattern pattern : patterns) { if (matches(input, pattern)) { return true; @@ -60,16 +150,18 @@ public class RegexUtil { return false; } - public static boolean matchesAnd(@Nullable CharSequence input, String... regexes) { - for (String regex : regexes) { - if (!matches(input, regex)) { - return false; - } + /** + * 判断 {@code input} 是否匹配全部正则。 + * + * @param input 输入 + * @param patterns 正则 + * @return 判断结果 + */ + public static boolean matchAll(@Nullable final CharSequence input, final Pattern[] patterns) { + Preconditions.checkNotNull(patterns, "The patterns can not be null."); + if (input == null) { + return false; } - return true; - } - - public static boolean matchesAnd(@Nullable CharSequence input, Pattern... patterns) { for (Pattern pattern : patterns) { if (!matches(input, pattern)) { return false; @@ -78,7 +170,122 @@ public class RegexUtil { return true; } + /** + * 判断 {@code input} 是否匹配 {@code pattern}。 + * + * @param input 输入 + * @param pattern 正则表达式 + * @param cachePattern 是否缓存 {@link Pattern} 实例 + * @return 判断结果 + */ + public static boolean matches(@Nullable final CharSequence input, final String pattern, + final boolean cachePattern) { + return matches(input, getPattern(pattern, cachePattern)); + } + + /** + * 判断 {@code input} 是否匹配 {@code pattern}。不缓存 {@link Pattern} 实例。 + * + * @param input 输入 + * @param pattern 正则表达式 + * @return 判断结果 + */ + public static boolean matches(@Nullable final CharSequence input, final String pattern) { + return matches(input, getPattern(pattern)); + } + + /** + * 判断 {@code input} 是否匹配 {@code patterns} 中的一个。 + * + * @param input 输入 + * @param patterns 正则表达式 + * @param cachePattern 是否缓存 {@link Pattern} 实例 + * @return 判断结果 + */ + public static boolean matchOne(@Nullable final CharSequence input, final String[] patterns, + final boolean cachePattern) { + final Pattern[] patternSet = getPatterns(patterns, cachePattern); + return matchOne(input, patternSet); + } + + /** + * 判断 {@code input} 是否匹配 {@code patterns} 中的一个。不缓存 {@link Pattern} 实例。 + * + * @param input 输入 + * @param patterns 正则表达式 + * @return 判断结果 + */ + public static boolean matchOne(@Nullable final CharSequence input, final String[] patterns) { + final Pattern[] patternSet = getPatterns(patterns); + return matchOne(input, patternSet); + } + + /** + * 判断 {@code input} 是否匹配全部正则。 + * + * @param input 输入 + * @param patterns 正则表达式 + * @param cachePattern 是否缓存 {@link Pattern} 实例 + * @return 判断结果 + */ + public static boolean matchAll(@Nullable final CharSequence input, final String[] patterns, + final boolean cachePattern) { + final Pattern[] patternSet = getPatterns(patterns, cachePattern); + return matchAll(input, patternSet); + } + + /** + * 判断 {@code input} 是否匹配全部正则。不缓存 {@link Pattern} 实例。 + * + * @param input 输入 + * @param patterns 正则表达式 + * @return 判断结果 + */ + public static boolean matchAll(@Nullable final CharSequence input, final String[] patterns) { + final Pattern[] patternSet = getPatterns(patterns); + return matchAll(input, patternSet); + } + + /** + * 生成匹配器。 + * + * @param input 输入 + * @param pattern 正则 + * @return 结果 + */ + public static Matcher getMatcher(final CharSequence input, final Pattern pattern) { + Preconditions.checkNotNull(input, "The input can not be null"); + Preconditions.checkNotNull(pattern, "The pattern can not be null"); + return pattern.matcher(input); + } + + /** + * 生成匹配器。 + * + * @param input 输入 + * @param pattern 正则表达式 + * @param cachePattern 是否缓存 {@link Pattern} 实例 + * @return 结果 + */ + public static Matcher getMatcher(final CharSequence input, final String pattern, boolean cachePattern) { + Preconditions.checkNotNull(input, "The input can not be null"); + return getPattern(pattern, cachePattern).matcher(input); + } + + /** + * 生成匹配器。不缓存 {@link Pattern} 实例。 + * + * @param input 输入 + * @param pattern 正则表达式 + * @return 结果 + */ + public static Matcher getMatcher(final CharSequence input, final String pattern) { + Preconditions.checkNotNull(input, "The input can not be null"); + return getPattern(pattern).matcher(input); + } + private RegexUtil() { + // 不允许实例化 throw new IllegalStateException("Utility class"); } }