关于javascript:如何使用单个正则表达式解析“dd-MMM-yyyy”或“MMM-dd-yyyy”日期字符串?

How to parse “dd-MMM-yyyy” or “MMM-dd-yyyy” date string using single regular expression?

本问题已经有最佳答案,请猛点这里访问。

我正在获取日期字符串,如dd-MMM-yyyyMMM-dd-yyyy格式。我只想用一个正则表达式(不使用任何第三方插件)提取daymonthyear。有可能吗?


我会先反转月和日的位置,得到所有日期的相同格式:

1
2
3
4
5
6
7
8
9
10
11
12
function splitDate(input) {
    return input.replace(
        /^(\w+)-(\d+)/, '$2-$1'
    ).split('-');
}

var parts = splitDate('Feb-12-2012'); // ["12","Feb","2012"]
var parts = splitDate('12-Feb-2012'); // ["12","Feb","2012"]

var day = parts[0];
var month = parts[1];
var year = parts[2];

/^(\w+)-(\d+)/只匹配"mmm dd yyyy":

1
2
3
4
^       beginning of the input
(\w+)   a word character, one or more times ($1)
-       a dash
(\d+)   a digit, one or more times ($2)

。更进一步

既然您知道了如何分割输入,那么我希望通过将结果转换为日期对象来进一步了解这一点。首先,让我们打开chrome的控制台,快速检查输入是否可以按原样进行解析:

1
2
new Date('12-Feb-2012') // Sun Feb 12 2012...
new Date('Feb-12-2012') // Sun Feb 12 2012...

很明显,Chrome可以很好地完成这项工作。这很好,但是其他实现不一定以相同的方式运行,您应该更好地依赖于规范。幸运的是,有人已经为您检查了它们:未记录的支持日期。分析格式?

概括地说,解析您自己的格式的能力可能因实现而异。只有一种可靠的格式,即YYYY-MM-DDTHH:mm:ss.sssZ,其中每个字母(除了"t"和"z")代表一个数字。

准确地说,预计MM是一个数字。如果你想确保你的输入被正确地解析,你必须找到一种方法把月份部分转换成数字。让我们尝试一下:

1
2
3
4
5
6
var months = {
    Jan: '01', Feb: '02', Mar: '03', Apr: '04', May: '05', Jun: '06',
    Jul: '07', Aug: '08', Sep: '09', Oct: '10', Nov: '11', Dec: '12'
};
var parts = splitDate('Feb-12-2012'); // ["12","Feb","2012"]
parts[1] = months[parts[1]]; // parts -> ["12","02","2012"]

还不错,工作就快完成了。实际上,正如在规范中提到的,解析器接受日期格式,如YYYY-MM-DD,这非常容易实现:

1
2
parts = parts.reverse(); // ["2012","02","12"]
parts = parts.join('-'); //"2012-02-12"

让我们看看控制台上的内容:

1
new Date(parts) // Sun Feb 12 2012...

完成!

结案

或者,您可以这样做:

1
2
3
var parts = splitDate('Feb-12-2012'); // ["12","Feb","2012"]
parts[1] = months[parts[1]]; // parts -> ["12","02","2012"]
var date = new Date(parts[2], parts[1] - 1, parts[0]);

通过将进程隐藏到函数中,您可以更进一步:

1
2
3
4
5
6
7
8
9
10
function parseDate(input) {
    var map = {
        Jan: 0, Feb: 1, Mar: 2, Apr: 3, May: 4, Jun: 5,
        Jul: 6, Aug: 7, Sep: 8, Oct: 9, Nov: 10, Dec: 11
    };
    return (parseDate = function (input) {
        input = input.replace(/^(\w+)-(\d+)/, '$2-$1').split('-');
        return new Date(input[2], map[input[1]], input[0]);
    })(input);
};

用法示例:

1
2
var date = parseDate('12-Feb-2012'); // Sun Feb 12 2012...
var date = parseDate('Feb-12-2012'); // Sun Feb 12 2012...

请随时询问详情。


是的,这当然是可能的,但是您必须检查哪些捕获组匹配:

1
/^(?:(\d\d)-([a-z]{3})-(\d{4})|([a-z]{3})-(\d\d)-(\d{4}))$/i

如果匹配后定义了从31组,则使用dd-MMM-yyyy;如果定义了从46组,则使用另一组。

这个regex不做任何合理性检查,因此它也将匹配99-XXX-9999,但这是一个不同的问题。


首先,您可以将dd-MMM-yyyyMMM-dd-yyyy格式转换为dd-MMM-yyyy

使用:.replace(/([a-zA-Z]{3})-(\d{2})-(\d{4})/,"$2-$1-$3");

然后可以使用regex:/(\d+)-([a-zA-Z]{3})-(\d{4})/

代码:

1
2
3
4
5
6
var d="DEC-16-1990";
d=d.replace(/([a-zA-Z]{3})-(\d{2})-(\d{4})/,"$2-$1-$3");
var ar=d.match(/(\d+)-([a-zA-Z]{3})-(\d{4})/);
var day=ar[1];    //16
var month=ar[2];  //DEC
var year=ar[3];   //1990

演示


此变体添加了符号YYY MMM DD,允许使用单个数字的日数,并为语言独立性提供了月份名称的规范。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function parseDate (date, months) {
  var dateRE = /^(?:(\d\d?)-(%m)-(\d{4})|(%m)-(\d\d?)-(\d{4})|(\d{4})-(%m)-(\d\d?))$/;
  if (!months)
    months = 'jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec';

  dateRE = RegExp (('' + dateRE).replace (/%m/g, months).slice (1, -1), 'i');

  date = date.match (dateRE) || [date];

  return date.length == 1 ?
    date[0] :  // Return string if parse error
    [date[1] || date[4] || date[7], date[2] || date[5] || date[8], date[3] || date[6]|| date[9]];
}


console.log (parseDate ("13-feb-2014"));
console.log (parseDate ("Feb-13-2014"));
console.log (parseDate ("2014-FEB-13"));
console.log (parseDate ("1-feb-2014"));
console.log (parseDate ("Feb-1-2014"));
console.log (parseDate ("2014-FEB-1"));
console.log (parseDate ("01-fev-678"));

显示器

1
2
3
4
5
6
7
["13","feb","2014"]
["Feb","13","2014"]
["2014","FEB","13"]
["1","feb","2014"]
["Feb","1","2014"]
["2014","FEB","1"]
"01-fev-678"