Regex 匹配YYMMDD但不匹配更长数字的bash正则表达式 一般问题

Regex 匹配YYMMDD但不匹配更长数字的bash正则表达式 一般问题,regex,bash,macos,Regex,Bash,Macos,我试图理解,在编写正则表达式时,如何防止在寻找到的模式之前或之后存在某种模式 一个更具体的例子 我正在寻找一个正则表达式,它将在一个长字符串中匹配YYMMDD(([0-9]{2})(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1]))格式的日期,同时忽略更长的数字序列 它应该能够匹配: 文本151124moretext 123text 151124moretext 文本151124 text 151124moretext1944 151124 但是应该忽略:

我试图理解,在编写正则表达式时,如何防止在寻找到的模式之前或之后存在某种模式

一个更具体的例子 我正在寻找一个正则表达式,它将在一个长字符串中匹配YYMMDD(
([0-9]{2})(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])
)格式的日期,同时忽略更长的数字序列

它应该能够匹配:

  • 文本151124moretext
  • 123text 151124moretext
  • 文本151124
  • text 151124moretext1944
  • 151124
但是应该忽略

  • 文本15112412更多文本 (原因:它有8个数字而不是6个)
  • 151324 (原因:它不是有效日期YYMMDD-没有第13个月)
我如何确保如果一个数字的多于这6位,那么它不会在一个正则表达式中作为日期提取(这意味着我宁愿避免预处理字符串) 我想到了
\D((19 | 20)([0-9]{2})(0[1-9]| 1[0-2])(0[1-9]|[1-2][0-9]| 3[0-1])\D
但这难道不意味着前后必须有一些字符吗

我正在使用Bash3.2(ERE)

谢谢

试试看:

#!/usr/bin/env bash

extract_date() {
    local string="$1"
    local _date=`echo "$string" | sed -E 's/.*[^0-9]([0-9]{6})[^0-9].*/\1/'`
    #date -d $_date &> /dev/null # for Linux
    date -jf '%y%m%d' $_date &> /dev/null # for MacOS
    if [ $? -eq 0 ]; then
        echo $_date
    else
        return 1
    fi
}


extract_date text15111224moretext # ignore n_digits > 6
extract_date text151125moretext # take
extract_date text151132 # # ignore day 32
extract_date text151324moretext1944 # ignore month 13
extract_date text150931moretext1944 # ignore 31 Sept
extract_date 151126 # take
输出:

151125
151126

如果您的令牌是行分隔的(即每行只有一个令牌):

基本上,这个正则表达式寻找:

  • 字符串开头任意数量的非数字
  • 正好是6位数
  • 任意数量的非数字,直到字符串的结尾,或至少一个非数字和至少一个数字(最多6个)

此正则表达式传递所有给定的示例输入。

您可以使用非捕获组来定义日期正则表达式两侧的非数字。我成功地使用了这个表达式和您相同的测试数据

(?:\D)([0-9]{2})(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])(?:\D)

如果你使用
(^[0-9])…([^0-9]|$)
?什么没有断言?没有
bash
3.4;你是说OSX附带的3.2版本,还是你自己安装的4.3版本?@chepner,啊,我错了——OSX附带的是3.2版本!谢谢你指出@sin,这是一个好机会!所有这些regex的味道都让我头疼,作为一个初学者,这真的让人望而生畏——看来我真正需要的是消极的前瞻。似乎ERE不支持消极前瞻-不是吗?谢谢@gregoux,这是一个有趣的方法!尽管如此,我还是在寻找一个能做到这一点的单一正则表达式;原因是我需要概括。现在我想起来了,表达我的问题的一个更好的方式是:在编写正则表达式时,我试图理解如何防止在寻找的模式之前或之后存在某种模式!然后您可以向上投票;)。您面临的问题是如何管理像9月31日False和2月28日False这样的案例。sed-r似乎在OSX中不起作用。sed-E代表增强(与扩展不同,但在特定表达式中它就足够了)()。OSX上的日期也不同;日期-d不起作用:我不得不用
date-jf“%y%m%d”$\u date&>/dev/null
-如果您同意这些更改,您可以将它们集成到您的答案中,我将接受它们!作为旁注,
150931
通过
日期
评估(至少在OSX上)并转换为2015/10/01!对我来说,这是无关紧要的。谢谢你,泰德X!但是,我似乎无法将\D和\D与bash的[[=~]]操作符一起使用;运算符=~仅限于ERE-我弄错了吗?不确定这是否是我的错误,但似乎ERE不支持非捕获组和\D、\D等?
(?:\D)([0-9]{2})(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])(?:\D)