This commit is contained in:
Looly 2024-06-27 12:04:00 +08:00
parent 46ada04f95
commit e56e10b75c
5 changed files with 139 additions and 124 deletions

View File

@ -0,0 +1,84 @@
/*
* Copyright (c) 2024. looly(loolly@aliyun.com)
* Hutool is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* https://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package org.dromara.hutool.core.date.format.parser;
import java.util.Date;
import java.util.regex.Pattern;
/**
* 全局正则日期解析器<br>
* 通过使用预定义或自定义的正则规则解析日期字符串
*
* @author Looly
* @since 6.0.0
*/
public class GlobalRegexDateParser {
// hh:mm:ss.SSSSZ hh:mm:ss.SSSS hh:mm:ss hh:mm
private static final String timeRegex = "(" +
"\\s(?<hour>\\d{1,2})" +
":(?<minute>\\d{1,2})" +
"(:(?<second>\\d{1,2}))?" +
"(?:[.,](?<ns>\\d{1,9}))?(?<zero>z)?" +
"(\\s?(?<m>am|pm))?" +
")?";
// +08:00 +0800 +08
private static final String zoneOffsetRegex = "(\\s?(?<zoneOffset>[-+]\\d{1,2}:?(?:\\d{2})?))?";
// CST UTC (CST)
private static final String zoneNameRegex = "(\\s[(]?(?<zoneName>[a-z ]+)[)]?)?";
private static final RegexDateParser PARSER;
static {
final String dateRegexMonthFirst = "(?<month>\\w+{3,9})\\W+(?<day>\\d{1,2})(?:th)?\\W+(?<year>\\d{2,4})";
PARSER = RegexDateParser.of(
// 年开头
//月开头类似May 8, 2009 5:57:51
dateRegexMonthFirst + timeRegex + zoneOffsetRegex
// 周开头
// 日开头
);
}
/**
* 解析日期此方法线程安全
*
* @param source 日期字符串
* @return 日期
*/
public static Date parse(final CharSequence source) {
return PARSER.parse(source);
}
/**
* 新增自定义日期正则
*
* @param regex 日期正则
*/
synchronized public static void registerRegex(final String regex) {
PARSER.addRegex(regex);
}
/**
* 新增自定义日期正则
*
* @param pattern 日期正则
*/
synchronized public static void registerPattern(final Pattern pattern) {
PARSER.addPattern(pattern);
}
}

View File

@ -12,74 +12,98 @@
package org.dromara.hutool.core.date.format.parser;
import org.dromara.hutool.core.collection.ListUtil;
import org.dromara.hutool.core.date.*;
import org.dromara.hutool.core.lang.Opt;
import org.dromara.hutool.core.regex.ReUtil;
import org.dromara.hutool.core.text.StrUtil;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 正则日期解析器<br>
* 通过定义一个命名分组的正则匹配日期格式使用正则分组获取日期各部分的值命名分组使用{@code (?<xxx>子表达式) }表示<br>
* <pre>{@code
* ^(?<year>\d{4})(?<month>\d{2})$ 匹配 201909
* }</pre>
* 使用正则列表方式的日期解析器<br>
* 通过定义若干的日期正则遍历匹配到给定正则后按照正则方式解析为日期
*
* @author Looly
* @since 6.0.0
*/
public class RegexDateParser implements PredicateDateParser {
public class RegexDateParser implements DateParser, Serializable {
private static final long serialVersionUID = 1L;
private static final int[] NSS = {100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1};
/**
* 根据给定带名称分组正则创建RegexDateParser
* 根据给定的正则列表创建RegexListDateParser
*
* @param regex 正则表达式
* @return RegexDateParser
* @param regexes 正则列表默认忽略大小写
* @return RegexListDateParser
*/
public static RegexDateParser of(final String regex) {
// 日期正则忽略大小写
return of(Pattern.compile(regex, Pattern.CASE_INSENSITIVE));
public static RegexDateParser of(final String... regexes) {
final List<Pattern> patternList = new ArrayList<>(regexes.length);
for (final String regex : regexes) {
patternList.add(Pattern.compile(regex, Pattern.CASE_INSENSITIVE));
}
return new RegexDateParser(patternList);
}
/**
* 根据给定带名称分组正则创建RegexDateParser
* 根据给定的正则列表创建RegexListDateParser
*
* @param pattern 正则达式
* @return RegexDateParser
* @param patterns 正则
* @return RegexListDateParser
*/
public static RegexDateParser of(final Pattern pattern) {
return new RegexDateParser(pattern);
public static RegexDateParser of(final Pattern... patterns) {
return new RegexDateParser(ListUtil.of(patterns));
}
private final Pattern pattern;
private final List<Pattern> patterns;
/**
* 构造
*
* @param pattern 正则达式
* @param patterns 正则
*/
public RegexDateParser(final Pattern pattern) {
this.pattern = pattern;
public RegexDateParser(final List<Pattern> patterns) {
this.patterns = patterns;
}
@Override
public boolean test(final CharSequence source) {
return ReUtil.isMatch(this.pattern, source);
/**
* 新增自定义日期正则
*
* @param regex 日期正则
* @return this
*/
public RegexDateParser addRegex(final String regex) {
// 日期正则忽略大小写
return addPattern(Pattern.compile(regex, Pattern.CASE_INSENSITIVE));
}
/**
* 新增自定义日期正则
*
* @param pattern 日期正则
* @return this
*/
public RegexDateParser addPattern(final Pattern pattern) {
this.patterns.add(pattern);
return this;
}
@Override
public Date parse(final CharSequence source) throws DateException {
final Matcher matcher = this.pattern.matcher(source);
if (!matcher.matches()) {
throw new DateException("Invalid date string: [{}], not match the date regex: [{}].", source, this.pattern.pattern());
Matcher matcher;
for (final Pattern pattern : this.patterns) {
matcher = pattern.matcher(source);
if (matcher.matches()) {
return parse(matcher);
}
}
return parse(matcher);
throw new DateException("No valid pattern for date string: [{}]", source);
}
/**
@ -89,7 +113,7 @@ public class RegexDateParser implements PredicateDateParser {
* @return 日期
* @throws DateException 日期解析异常
*/
public static Date parse(final Matcher matcher) throws DateException {
private static Date parse(final Matcher matcher) throws DateException {
// 毫秒时间戳
final String millisecond = ReUtil.group(matcher, "millisecond");
if (StrUtil.isNotEmpty(millisecond)) {

View File

@ -1,88 +0,0 @@
/*
* Copyright (c) 2024. looly(loolly@aliyun.com)
* Hutool is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* https://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package org.dromara.hutool.core.date.format.parser;
import org.dromara.hutool.core.collection.ListUtil;
import org.dromara.hutool.core.date.DateException;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 使用正则列表方式的日期解析器<br>
* 通过定义若干的日期正则遍历匹配到给定正则后按照正则方式解析为日期
*
* @author Looly
*/
public class RegexListDateParser implements DateParser, Serializable {
private static final long serialVersionUID = 1L;
/**
* 根据给定的正则列表创建RegexListDateParser
*
* @param patterns 正则列表
* @return RegexListDateParser
*/
public static RegexListDateParser of(final Pattern... patterns) {
return new RegexListDateParser(ListUtil.of(patterns));
}
private final List<Pattern> patterns;
/**
* 构造
*
* @param patterns 正则列表
*/
public RegexListDateParser(final List<Pattern> patterns) {
this.patterns = patterns;
}
/**
* 新增自定义日期正则
*
* @param regex 日期正则
* @return this
*/
public RegexListDateParser addRegex(final String regex) {
// 日期正则忽略大小写
return addPattern(Pattern.compile(regex, Pattern.CASE_INSENSITIVE));
}
/**
* 新增自定义日期正则
*
* @param pattern 日期正则
* @return this
*/
public RegexListDateParser addPattern(final Pattern pattern) {
this.patterns.add(pattern);
return this;
}
@Override
public Date parse(final CharSequence source) throws DateException {
Matcher matcher;
for (final Pattern pattern : this.patterns) {
matcher = pattern.matcher(source);
if (matcher.matches()) {
return RegexDateParser.parse(matcher);
}
}
throw new DateException("No valid pattern for date string: [{}]", source);
}
}

View File

@ -71,11 +71,6 @@ public class RegexDateParserTest {
void parseMonthFirstTest() {
final String dateRegex = "(?<month>\\w+{3,9})\\W+(?<day>\\d{1,2})(?:th)?\\W+(?<year>\\d{2,4})";
// +08:00
// +0800
// +08
final String zoneOffsetRegex = "(\\s?(?<zoneOffset>[-+]\\d{1,2}:?(?:\\d{2})?))?";
// May 8, 2009 5:57:51
final RegexDateParser parser = RegexDateParser.of(dateRegex + timeRegex + zoneOffsetRegex);

View File

@ -60,7 +60,7 @@ public class HttpHeaderUtil {
*/
public static String getFileNameFromDisposition(final Map<String, List<String>> headers, String paramName) {
paramName = ObjUtil.defaultIfNull(paramName, "filename");
final List<String> dispositions = headerList(headers, HeaderName.CONTENT_DISPOSITION.name());
final List<String> dispositions = headerList(headers, HeaderName.CONTENT_DISPOSITION.getValue());
String fileName = null;
if (CollUtil.isNotEmpty(dispositions)) {