【问题标题】:RegEx for validating correct ISO8601 date string [duplicate]用于验证正确 ISO8601 日期字符串的正则表达式 [重复]
【发布时间】:2019-05-10 14:44:14
【问题描述】:

例如:2013-08-11T17:22:04.51+01:00

在这个stackoverflow answer 中覆盖没有 .51 部分的 ISODateTime。

请帮助纠正这个正则表达式

^(?:[1-9]\d{3}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1\d|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[1-9]\d(?:0[48]|[2468][048]|[13579][26])|(?:[2468][048]|[13579][26])00)-02-29)T(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:Z|[+-][01]\d:[0-5]\d)$

处理我的格式。

【问题讨论】:

标签: java regex isodate


【解决方案1】:

正则表达式有时很方便,但通常难以阅读并且(正如您所经历的那样)难以调试。 Java 内置了对 ISO 8601 格式的解析和验证,它接受带有和不带小数的字符串,例如 .51。我了解您之所以问,是因为您需要通过 javax.validation 进行验证,这需要一个正则表达式。所以只针对其他读者:选择很明显:不要在这里使用正则表达式。

    try {
        OffsetDateTime.parse("2013-08-11T17:22:04.51+01:00");
        System.out.println("Valid ISO 8601");
    } catch (DateTimeParseException e) {
        System.out.println("Not valid ISO 8601");
    }

有效的 ISO 8601

警告:OffsetDateTime.parse 仍然不接受 ISO 8601 的所有变体,但变体比您的正则表达式要多得多。

【讨论】:

  • 这当然是正确的答案。
【解决方案2】:

使用捕获组,您可以简单地设计一个表达式来捕获您希望从输入中获取的任何内容。例如this expression,

(\d{4}-\d{2}-\d{2})[A-Z]+(\d{2}:\d{2}:\d{2}).([0-9+-:]+)

将您的输入分为三个捕获组,您可以使用 $1-$3 简单地调用它们。

您还可以在[] 中添加您可能想要的任何字符。

正则表达式描述图

此图表显示了表达式的工作原理,您可以在此 link 中可视化其他表达式:

Java 测试

import java.util.regex.Matcher;
import java.util.regex.Pattern;

final String regex = "(\\d{4}-\\d{2}-\\d{2})[A-Z]+(\\d{2}:\\d{2}:\\d{2}).([0-9+-:]+)";
final String string = "2013-08-11T17:22:04.51+01:00";
final String subst = "\\1 \\2 \\3";

final Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);
final Matcher matcher = pattern.matcher(string);

// The substituted value will be contained in the result variable
final String result = matcher.replaceAll(subst);

System.out.println("Substitution result: " + result);

JavaScript 演示

const regex = /(\d{4}-\d{2}-\d{2})[A-Z]+(\d{2}:\d{2}:\d{2}).([0-9+-:]+)/gm;
const str = `2013-08-11T17:22:04.51+01:00`;
const subst = `\nGroup 1: $1\nGroup 2: $2\nGroup 3: $3\n`;

// The substituted value will be contained in the result variable
const result = str.replace(regex, subst);

console.log('Substitution result: ', result);

基本性能测试

这个 JavaScript sn-p 显示了使用简单的 100 万次 for 循环的表达式性能。

const repeat = 1000000;
const start = Date.now();

for (var i = repeat; i >= 0; i--) {
	const string = '2013-08-11T17:22:04.51+01:00';
	const regex = /(\d{4}-\d{2}-\d{2})[A-Z]+(\d{2}:\d{2}:\d{2}).([0-9+-:]+)/gm;
	var match = string.replace(regex, "\nGroup #1: $1 \n Group #2: $2 \n Group #3: $3 \n");
}

const end = Date.now() - start;
console.log("YAAAY! \"" + match + "\" is a match ??? ");
console.log(end / 1000 + " is the runtime of " + repeat + " times benchmark test. ? ");

【讨论】:

    【解决方案3】:

    这个正则表达式应该可以完成这项工作:

    ^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$
    

    参考。 https://www.myintervals.com/blog/2009/05/20/iso-8601-date-validation-that-doesnt-suck/

    【讨论】:

    • 感谢@ibiza 它是有效的。
    • 开头[\+-]?的目的是什么?还有(?!\d{2}\b)? ...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-11-02
    • 1970-01-01
    • 2020-09-16
    • 1970-01-01
    • 2014-12-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多