我正在制作一个日期匹配的正则表达式,目前进展顺利,我已经得到了如下的代码:
"/(?:[0-3])?[0-9]-(?:[0-1])?[0-9]-(?:20)[0-1][0-9]/"
这将(希望如此)匹配21世纪的单个或双位数日/月份和双位或四位数年份。经过一些尝试和错误,我已经做到了这一点。
但是,我对这些结果有两个简单的问题:
(?: )
这是什么意思?显然这是一个非匹配组,但是...末尾的
?
是什么意思?例如(? )?
我正在制作一个日期匹配的正则表达式,目前进展顺利,我已经得到了如下的代码:
"/(?:[0-3])?[0-9]-(?:[0-1])?[0-9]-(?:20)[0-1][0-9]/"
这将(希望如此)匹配21世纪的单个或双位数日/月份和双位或四位数年份。经过一些尝试和错误,我已经做到了这一点。
但是,我对这些结果有两个简单的问题:
(?: )
这是什么意思?显然这是一个非匹配组,但是...
末尾的 ?
是什么意思?例如 (? )?
[再次修改格式并修复介绍部分]
这是一则评论和答案。
答案部分... 我同意alex之前的答案。
(?: )
与( )
相反,用于避免捕获文本,通常是为了减少与所需内容混杂的反向引用或提高速度性能。
跟在(?: )
后面的问号(或者除* + ?
或{}
之外的任何符号)表示先前的项可能存在于一个合法匹配中,也可能不存在。例如,/z34?/
将匹配z3和z34,但不会匹配z35或z等。
评论部分... 我对你正在处理的正则表达式进行了一些改进:
(?:^|\s)(0?[1-9]|[1-2][0-9]|30|31)-(0?[1-9]|10|11|12)-((?:20)?[0-9][0-9])(?:\s|$)
-- 首先,它避免了像0-0-2011这样的日期格式。(?:^|\s)(?:(?:(0?[1-9]|[1-2][0-9]|30|31)-(0?[13578]|10|12))|(?:(0?[1-9]|[1-2][0-9]|30)-(0?[469]|11))|(?:(0?[1-9]|[1-2][0-9])-(0?2)))-((?:20)?[0-9][0-9])(?:\s|$)
此外,我假设日期前后会有一个空格(或行首/行尾),但你可能需要调整它(例如,允许标点符号)。其他地方的评论者提到了这个资源,你可能会发现它很有用:http://rubular.com/。子模式
子模式由括号(圆括号)分隔,可以嵌套。将模式的一部分标记为子模式会做两件事:
例如,如果字符串"the red king"与模式the ((red|white) (king|queen))匹配,则捕获的子字符串是"red king"、"red"和"king",编号分别为1、2和3。
普通括号具有两个功能的事实并不总是有帮助的。通常需要分组子模式而不需要捕获要求。如果左括号后面跟着"?: ",则该子模式不执行任何捕获,并且在计算任何后续捕获子模式的编号时不计数。例如,如果字符串"the white queen"与模式the ((?:red|white) (king|queen))匹配,则捕获的子字符串为"white queen"和"queen",编号分别为1和2。最大捕获子字符串数量为65535。但是,根据libpcre的配置选项,可能无法编译这样大的模式。
作为一种方便的简写方式,如果在非捕获子模式的开头需要任何选项设置,则选项字母可以出现在"?"和":"之间。因此,以下两个模式:
(?i:saturday|sunday)
(?:(?i)saturday|sunday)
准确匹配相同的字符串集合。由于备选分支从左到右尝试,并且选项不会在子模式结束之前重置,因此一个分支中的选项设置会影响后续的分支,所以上述模式匹配"SUNDAY"以及"Saturday"。
可以使用语法(?Ppattern)来命名子模式。这个子模式将按其正常的数字位置和名称被索引到匹配数组中。PHP 5.2.2 引入了两种替代语法 (?pattern) 和 (?'name'pattern)。
有时需要在正则表达式中拥有多个匹配但交替的子组。通常,即使只有其中一个可能匹配,每个子组也会有自己的反向引用编号。为了解决这个问题,(?| 语法允许有重复的编号。考虑以下正则表达式与字符串Sunday匹配:
(?:(Sat)ur|(Sun))day
这里 Sun 存储在反向引用 2 中,而反向引用 1 是空的。匹配会将 Sat 存储在反向引用 1 中,而反向引用 2 不存在。将模式更改为使用 (?| 可以解决这个问题:
(?|(Sat)ur|(Sun))day
/[0-3]?[0-9]-[0-1]?[0-9]-(?:20)?[0-1][0-9]/
,然后在组件上运行checkdate()
来处理虚假日期。 - Ben