QML中日期和时间的正则表达式(DD/MM/YYYY hh:mm:ss)
Regular Expression for date and time(DD/MM/YYYY hh:mm:ss) in QML
在 QML2 中,我没有找到任何 Calender
控件,我已经实现了一个将日期和时间作为输入的控件,我正在使用正则表达式进行验证,该表达式匹配包括闰年和其他日期在内的日期验证。
主要问题是space/backspace也应该算一个有效例如:
\s\s/\s\s/\s\s \s\s:\s\s:\s\s
代码如下:
TextField{
id:textEditDate
width:parent.width * 0.50
height:parent.height
text : "01/01/2017 00:00:00"
inputMask: "99/99/9999 99:99:99"
validator: RegExpValidator { regExp: /^(((([0\s][1-9\s]|[1\s][0-9\s]|[2\s][0-8\s])[\/]([0\s][1-9\s]|[1\s][012\s]))|((29|30|31)[\/]([0\s][13578\s]|[1\s][02\s]))|((29|30)[\/]([0\s][4,6,9]|11)))[\/]([19\s[2-9\s][0-9\s])\d\d|(^29[\/]02[\/]([19\s]|[2-9\s][0-9\s])(00|04|08|12|16|20|24|28|32|36|40|44|48|52|56|60|64|68|72|76|80|84|88|92|96)))\s([0-1\s]?[0-9\s]|2[0-3\s]):([0-5\s][0-9\s]):([0-5\s][0-9\s])$/}
horizontalAlignment: Text.AlignHCenter
inputMethodHints: Qt.ImhDigitsOnly
}
现在,除年份外一切正常,我无法匹配 backspace/space 年份,用户无法清除年份。
你能建议如何实现这一目标吗?或者有没有其他方法可以做到这一点。
您匹配年份的顺序是:
([19\s[2-9\s][0-9\s])\d\d
看起来格式不正确,因为括号不匹配。
此外,两个数字的存在(使用\d
)意味着表达式将不匹配白色space。
回答
简介
所以我决定制作一个真正适用于闰年的非常好的正则表达式!然后我添加了您需要的其余逻辑,瞧,太美了!
代码
(?(DEFINE)
(?# Date )
(?# Day ranges )
(?<d_day28>0[1-9]|1\d|2[0-8])
(?<d_day29>0[1-9]|1\d|2\d)
(?<d_day30>0[1-9]|1\d|2\d|30)
(?<d_day31>0[1-9]|1\d|2\d|3[01])
(?# Month specifications )
(?<d_month28>02)
(?<d_month29>02)
(?<d_month30>0[469]|11)
(?<d_month31>0[13578]|1[02])
(?# Year specifications )
(?<d_year>\d+)
(?<d_yearLeap>(?:\d*?(?:(?:(?!00)[02468][048]|[13579][26])|(?:(?:[02468][048]|[13579][26])00))|[48]00|[48])(?=\D))
(?# Valid date formats )
(?<d_format>
(?&d_day28)\/(?&d_month28)\/(?&d_year)|
(?&d_day29)\/(?&d_month29)\/(?&d_yearLeap)|
(?&d_day30)\/(?&d_month30)\/(?&d_year)|
(?&d_day31)\/(?&d_month31)\/(?&d_year)
)
(?# Time )
(?# Time properties )
(?<t_period12>(?i)[ap]m|[ap]\.m\.(?-i))
(?# Hours )
(?<t_hours12>0\d|1[01])
(?<t_hours24>[01]\d|2[0-3])
(?# Minutes )
(?<t_minutes>[0-5]\d)
(?# Seconds )
(?<t_seconds>[0-5]\d)
(?# Milliseconds )
(?<t_milliseconds>\d{3})
(?# Valid time formats )
(?<t_format>
(?&t_hours12):(?&t_minutes):(?&t_seconds)(?:\.(?&t_milliseconds))?\ ?(?&t_period12)|
(?&t_hours24):(?&t_minutes):(?&t_seconds)(?:\.(?&t_milliseconds))?
)
(?# Datetime )
(?<dt_format>(?&d_format)\ (?&t_format))
)
\b(?&dt_format)\b
或者在一行中...
\b(?:(?:0[1-9]|1\d|2[0-8])\/(?:02)\/(?:\d+)|(?:0[1-9]|1\d|2\d)\/(?:02)\/(?:(?:\d*?(?:(?:(?!00)[02468][048]|[13579][26])|(?:(?:[02468][048]|[13579][26])00))|[48]00|[48])(?=\D))|(?:0[1-9]|1\d|2\d|30)\/(?:0[469]|11)\/(?:\d+)|(?:0[1-9]|1\d|2\d|3[01])\/(?:0[13578]|1[02])\/(?:\d+))\ (?:(?:0\d|1[01]):(?:[0-5]\d):(?:[0-5]\d)(?:\.(?:\d{3}))?\ ?(?:(?i)[ap]m|[ap]\.m\.(?-i))|(?:[01]\d|2[0-3]):(?:[0-5]\d):(?:[0-5]\d)(?:\.(?:\d{3}))?)\b
说明
我将解释第一个版本,因为第二个版本只是它的精简版。请注意,可以轻松更改正则表达式以适应更多格式(只接受一种略有变化的格式,但这是一个非常可定制的正则表达式)。
- d_days28:匹配从
01
到28
的任意数字
- d_days29:匹配从
01
到29
的任意数字
- d_days30:匹配从
01
到30
的任意数字
- d_days31:匹配从
01
到31
的任意数字
- d_month28:匹配可能只有 28 天的月份(二月 - 因此
02
)
- d_month29:匹配可能只有 29 天的月份(二月 - 因此
02
)
- d_month30:匹配只有 30 天的月份(四月、六月、九月、十一月 - 因此
04, 06, 09, 11
)
- d_month31:匹配只有31天的月份(一月、三月、五月、七月、八月、十月, 十二月 - 因此
01, 03, 05, 07, 08, 10, 12
)
- d_year:匹配任意年份(必须至少有一个数字
\d
)
- d_yearLeap:为了更清楚起见,我将把它分成多个部分
\d*?
- 匹配任意数量的数字,但尽可能少
- 符合下列其中一项
(?:(?:(?!00)[02468][048]|[13579][26])|(?:(?:[02468][048]|[13579][26])00))
- 匹配以下其中一项
(?:(?!00)[02468][048]|[13579][26])
- 匹配以下其中一项
02468
之一,后跟048
之一,但不是00
13579
之一,后跟26
之一
(?:(?:[02468][048]|[13579][26])00)
- 匹配以下其中一项,后跟 00
02468
之一,后跟048
之一
13579
之一,后跟26
之一
[48]00
- 匹配 400
或 800
[48]
- 匹配 4
或 8
(?=\D|\b)
- 确保后面是非数字字符 \D
或单词边界字符 \b
- d_format:这指向前面的组,以确保月份格式正确并匹配 days/month 和 days/year(leap year) 要求,以便我们确保正确的日期验证
- t_period:添加此内容是为了防止其他人出于验证目的需要此内容
- 确保句点是
am, pm, a.m, p.m
或其各自的大写版本(包括使用多个大小写的 a.M
等)
- t_hours12:匹配从
00
到11
的任何时间
- t_hours24:匹配从
00
到23
的任何时间
- t_minutes:匹配从
00
到59
的任意分钟
- t_seconds:匹配从
00
到59
的任意秒数
- t_milliseconds:匹配任意3位数字(
000
到999
)
- t_format:这指向前面的组以确保时间格式正确。我已经添加了一个额外的时间设置(以及一个包括毫秒和时间段的附加项供其他人使用)
- dt_format:要检查的日期时间格式(在您的情况下是
date time
- 用 space [=198= 分隔]字符)
- 定义块之后是
\b(?&dt_format)\b
,它简单地匹配上面指定的dt_format
,确保它之前和取代它的是单词边界字符(或没有字符)\b
闰年
进一步了解正则表达式的闰年部分...
我假设如下:
- 所有年份都是 不是 闰年,除非下列情况为真
- ((年份模
4
是 0
) AND (年份模 100
不是 0
)) OR(年模 400
是 0
)
- 来源:leap year calculation
- 闰年一直存在(至少从第 1 年开始)- 因为我不想开始假设并做更多研究。
正则表达式的工作原理是确保:
- 所有以
0, 4, 8
结尾的闰年 在 之前有一个 0, 2, 4, 6, 8
(所有这些都会在模数后产生 0
->即 24 % 4 = 0
)
- 所有以
2, 6
结尾的闰年 在 之前有一个 1, 3, 5, 7, 9
(所有这些都会在模数后产生 0
->即 32 % 4 = 0
)
- 对于 1. 和 2.,所有以
00
、 结尾的闰年都被取反((?!00)
这样做)
- 所有以
00
结尾的闰年 在 之前 1。和 2.(与 4 * 100 = 400
完全相同 - 除了最后两位数字外无需更改)
- 添加年份
400, 800, 4, 8
,因为它们不满足上述任何条件
编辑
2017 年 10 月 25 日
感谢 @sln for the input on the leap year's functionality. The regex below performs slightly faster due to changes provided in the comments of this answer by sln(关于一个单独的问题)。在闰年部分将 (?:(?!00)[02468][048]|[13579][26])
更改为 (?:0[48]|[13579][26]|[2468][048])
。
(?(DEFINE)
(?# Date )
(?# Day ranges )
(?<d_day28>0[1-9]|1\d|2[0-8])
(?<d_day29>0[1-9]|1\d|2\d)
(?<d_day30>0[1-9]|1\d|2\d|30)
(?<d_day31>0[1-9]|1\d|2\d|3[01])
(?# Month specifications )
(?<d_month28>02)
(?<d_month29>02)
(?<d_month30>0[469]|11)
(?<d_month31>0[13578]|1[02])
(?# Year specifications )
(?<d_year>\d+)
(?<d_yearLeap>(?:\d*?(?:(?:0[48]|[13579][26]|[2468][048])|(?:(?:[02468][048]|[13579][26])00))|[48]00|[48])(?=\D|\b))
(?# Valid date formats )
(?<d_format>
(?&d_day28)\/(?&d_month28)\/(?&d_year)|
(?&d_day29)\/(?&d_month29)\/(?&d_yearLeap)|
(?&d_day30)\/(?&d_month30)\/(?&d_year)|
(?&d_day31)\/(?&d_month31)\/(?&d_year)
)
(?# Time )
(?# Time properties )
(?<t_period12>(?i)[ap]m|[ap]\.m\.(?-i))
(?# Hours )
(?<t_hours12>0\d|1[01])
(?<t_hours24>[01]\d|2[0-3])
(?# Minutes )
(?<t_minutes>[0-5]\d)
(?# Seconds )
(?<t_seconds>[0-5]\d)
(?# Milliseconds )
(?<t_milliseconds>\d{3})
(?# Valid time formats )
(?<t_format>
(?&t_hours12):(?&t_minutes):(?&t_seconds)(?:\.(?&t_milliseconds))?\ ?(?&t_period12)|
(?&t_hours24):(?&t_minutes):(?&t_seconds)(?:\.(?&t_milliseconds))?
)
(?# Datetime )
(?<dt_format>(?&d_format)\ (?&t_format))
)
\b(?&dt_format)\b
在 QML2 中,我没有找到任何 Calender
控件,我已经实现了一个将日期和时间作为输入的控件,我正在使用正则表达式进行验证,该表达式匹配包括闰年和其他日期在内的日期验证。
主要问题是space/backspace也应该算一个有效例如:
\s\s/\s\s/\s\s \s\s:\s\s:\s\s
代码如下:
TextField{
id:textEditDate
width:parent.width * 0.50
height:parent.height
text : "01/01/2017 00:00:00"
inputMask: "99/99/9999 99:99:99"
validator: RegExpValidator { regExp: /^(((([0\s][1-9\s]|[1\s][0-9\s]|[2\s][0-8\s])[\/]([0\s][1-9\s]|[1\s][012\s]))|((29|30|31)[\/]([0\s][13578\s]|[1\s][02\s]))|((29|30)[\/]([0\s][4,6,9]|11)))[\/]([19\s[2-9\s][0-9\s])\d\d|(^29[\/]02[\/]([19\s]|[2-9\s][0-9\s])(00|04|08|12|16|20|24|28|32|36|40|44|48|52|56|60|64|68|72|76|80|84|88|92|96)))\s([0-1\s]?[0-9\s]|2[0-3\s]):([0-5\s][0-9\s]):([0-5\s][0-9\s])$/}
horizontalAlignment: Text.AlignHCenter
inputMethodHints: Qt.ImhDigitsOnly
}
现在,除年份外一切正常,我无法匹配 backspace/space 年份,用户无法清除年份。
你能建议如何实现这一目标吗?或者有没有其他方法可以做到这一点。
您匹配年份的顺序是:
([19\s[2-9\s][0-9\s])\d\d
看起来格式不正确,因为括号不匹配。
此外,两个数字的存在(使用\d
)意味着表达式将不匹配白色space。
回答
简介
所以我决定制作一个真正适用于闰年的非常好的正则表达式!然后我添加了您需要的其余逻辑,瞧,太美了!
代码
(?(DEFINE)
(?# Date )
(?# Day ranges )
(?<d_day28>0[1-9]|1\d|2[0-8])
(?<d_day29>0[1-9]|1\d|2\d)
(?<d_day30>0[1-9]|1\d|2\d|30)
(?<d_day31>0[1-9]|1\d|2\d|3[01])
(?# Month specifications )
(?<d_month28>02)
(?<d_month29>02)
(?<d_month30>0[469]|11)
(?<d_month31>0[13578]|1[02])
(?# Year specifications )
(?<d_year>\d+)
(?<d_yearLeap>(?:\d*?(?:(?:(?!00)[02468][048]|[13579][26])|(?:(?:[02468][048]|[13579][26])00))|[48]00|[48])(?=\D))
(?# Valid date formats )
(?<d_format>
(?&d_day28)\/(?&d_month28)\/(?&d_year)|
(?&d_day29)\/(?&d_month29)\/(?&d_yearLeap)|
(?&d_day30)\/(?&d_month30)\/(?&d_year)|
(?&d_day31)\/(?&d_month31)\/(?&d_year)
)
(?# Time )
(?# Time properties )
(?<t_period12>(?i)[ap]m|[ap]\.m\.(?-i))
(?# Hours )
(?<t_hours12>0\d|1[01])
(?<t_hours24>[01]\d|2[0-3])
(?# Minutes )
(?<t_minutes>[0-5]\d)
(?# Seconds )
(?<t_seconds>[0-5]\d)
(?# Milliseconds )
(?<t_milliseconds>\d{3})
(?# Valid time formats )
(?<t_format>
(?&t_hours12):(?&t_minutes):(?&t_seconds)(?:\.(?&t_milliseconds))?\ ?(?&t_period12)|
(?&t_hours24):(?&t_minutes):(?&t_seconds)(?:\.(?&t_milliseconds))?
)
(?# Datetime )
(?<dt_format>(?&d_format)\ (?&t_format))
)
\b(?&dt_format)\b
或者在一行中...
\b(?:(?:0[1-9]|1\d|2[0-8])\/(?:02)\/(?:\d+)|(?:0[1-9]|1\d|2\d)\/(?:02)\/(?:(?:\d*?(?:(?:(?!00)[02468][048]|[13579][26])|(?:(?:[02468][048]|[13579][26])00))|[48]00|[48])(?=\D))|(?:0[1-9]|1\d|2\d|30)\/(?:0[469]|11)\/(?:\d+)|(?:0[1-9]|1\d|2\d|3[01])\/(?:0[13578]|1[02])\/(?:\d+))\ (?:(?:0\d|1[01]):(?:[0-5]\d):(?:[0-5]\d)(?:\.(?:\d{3}))?\ ?(?:(?i)[ap]m|[ap]\.m\.(?-i))|(?:[01]\d|2[0-3]):(?:[0-5]\d):(?:[0-5]\d)(?:\.(?:\d{3}))?)\b
说明
我将解释第一个版本,因为第二个版本只是它的精简版。请注意,可以轻松更改正则表达式以适应更多格式(只接受一种略有变化的格式,但这是一个非常可定制的正则表达式)。
- d_days28:匹配从
01
到28
的任意数字
- d_days29:匹配从
01
到29
的任意数字
- d_days30:匹配从
01
到30
的任意数字
- d_days31:匹配从
01
到31
的任意数字
- d_month28:匹配可能只有 28 天的月份(二月 - 因此
02
) - d_month29:匹配可能只有 29 天的月份(二月 - 因此
02
) - d_month30:匹配只有 30 天的月份(四月、六月、九月、十一月 - 因此
04, 06, 09, 11
) - d_month31:匹配只有31天的月份(一月、三月、五月、七月、八月、十月, 十二月 - 因此
01, 03, 05, 07, 08, 10, 12
) - d_year:匹配任意年份(必须至少有一个数字
\d
) - d_yearLeap:为了更清楚起见,我将把它分成多个部分
\d*?
- 匹配任意数量的数字,但尽可能少
- 符合下列其中一项
(?:(?:(?!00)[02468][048]|[13579][26])|(?:(?:[02468][048]|[13579][26])00))
- 匹配以下其中一项(?:(?!00)[02468][048]|[13579][26])
- 匹配以下其中一项02468
之一,后跟048
之一,但不是00
13579
之一,后跟26
之一
(?:(?:[02468][048]|[13579][26])00)
- 匹配以下其中一项,后跟00
02468
之一,后跟048
之一
13579
之一,后跟26
之一
[48]00
- 匹配400
或800
[48]
- 匹配4
或8
(?=\D|\b)
- 确保后面是非数字字符\D
或单词边界字符\b
- d_format:这指向前面的组,以确保月份格式正确并匹配 days/month 和 days/year(leap year) 要求,以便我们确保正确的日期验证
- t_period:添加此内容是为了防止其他人出于验证目的需要此内容
- 确保句点是
am, pm, a.m, p.m
或其各自的大写版本(包括使用多个大小写的a.M
等)
- 确保句点是
- t_hours12:匹配从
00
到11
的任何时间
- t_hours24:匹配从
00
到23
的任何时间
- t_minutes:匹配从
00
到59
的任意分钟
- t_seconds:匹配从
00
到59
的任意秒数
- t_milliseconds:匹配任意3位数字(
000
到999
) - t_format:这指向前面的组以确保时间格式正确。我已经添加了一个额外的时间设置(以及一个包括毫秒和时间段的附加项供其他人使用)
- dt_format:要检查的日期时间格式(在您的情况下是
date time
- 用 space [=198= 分隔]字符) - 定义块之后是
\b(?&dt_format)\b
,它简单地匹配上面指定的dt_format
,确保它之前和取代它的是单词边界字符(或没有字符)\b
闰年
进一步了解正则表达式的闰年部分...
我假设如下:
- 所有年份都是 不是 闰年,除非下列情况为真
- ((年份模
4
是0
) AND (年份模100
不是0
)) OR(年模400
是0
) - 来源:leap year calculation
- 闰年一直存在(至少从第 1 年开始)- 因为我不想开始假设并做更多研究。
- ((年份模
正则表达式的工作原理是确保:
- 所有以
0, 4, 8
结尾的闰年 在 之前有一个0, 2, 4, 6, 8
(所有这些都会在模数后产生0
->即24 % 4 = 0
) - 所有以
2, 6
结尾的闰年 在 之前有一个1, 3, 5, 7, 9
(所有这些都会在模数后产生0
->即32 % 4 = 0
) - 对于 1. 和 2.,所有以
00
、 结尾的闰年都被取反((?!00)
这样做) - 所有以
00
结尾的闰年 在 之前 1。和 2.(与4 * 100 = 400
完全相同 - 除了最后两位数字外无需更改) - 添加年份
400, 800, 4, 8
,因为它们不满足上述任何条件
编辑
2017 年 10 月 25 日
感谢 @sln for the input on the leap year's functionality. The regex below performs slightly faster due to changes provided in the comments of this answer by sln(关于一个单独的问题)。在闰年部分将 (?:(?!00)[02468][048]|[13579][26])
更改为 (?:0[48]|[13579][26]|[2468][048])
。
(?(DEFINE)
(?# Date )
(?# Day ranges )
(?<d_day28>0[1-9]|1\d|2[0-8])
(?<d_day29>0[1-9]|1\d|2\d)
(?<d_day30>0[1-9]|1\d|2\d|30)
(?<d_day31>0[1-9]|1\d|2\d|3[01])
(?# Month specifications )
(?<d_month28>02)
(?<d_month29>02)
(?<d_month30>0[469]|11)
(?<d_month31>0[13578]|1[02])
(?# Year specifications )
(?<d_year>\d+)
(?<d_yearLeap>(?:\d*?(?:(?:0[48]|[13579][26]|[2468][048])|(?:(?:[02468][048]|[13579][26])00))|[48]00|[48])(?=\D|\b))
(?# Valid date formats )
(?<d_format>
(?&d_day28)\/(?&d_month28)\/(?&d_year)|
(?&d_day29)\/(?&d_month29)\/(?&d_yearLeap)|
(?&d_day30)\/(?&d_month30)\/(?&d_year)|
(?&d_day31)\/(?&d_month31)\/(?&d_year)
)
(?# Time )
(?# Time properties )
(?<t_period12>(?i)[ap]m|[ap]\.m\.(?-i))
(?# Hours )
(?<t_hours12>0\d|1[01])
(?<t_hours24>[01]\d|2[0-3])
(?# Minutes )
(?<t_minutes>[0-5]\d)
(?# Seconds )
(?<t_seconds>[0-5]\d)
(?# Milliseconds )
(?<t_milliseconds>\d{3})
(?# Valid time formats )
(?<t_format>
(?&t_hours12):(?&t_minutes):(?&t_seconds)(?:\.(?&t_milliseconds))?\ ?(?&t_period12)|
(?&t_hours24):(?&t_minutes):(?&t_seconds)(?:\.(?&t_milliseconds))?
)
(?# Datetime )
(?<dt_format>(?&d_format)\ (?&t_format))
)
\b(?&dt_format)\b