返回列表 发帖
本帖最后由 qzwqzw 于 2011-5-30 17:53 编辑

OK
感谢提醒
我的关于“正向、反向”的提法有问题
/v开关的“不包含匹配”用在正则中
实际上是指“任一模式串均不匹配”
使用/v开关后不需要改变模式串
也可以可通过逆变&&后面的程序逻辑得到相同的效果

我所说的反向应该是指模式串的“反向”
即正向模式串的逆变

正向确实是“符合任意一条都匹配”
我的正向模式串正体现了这一特性

^[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]$
是判定日期串长度合法而非非法的
虽然使用/v或者逆变程序逻辑
可以独立地判定字符串长度非法
但是无法与逆向模式串结合使用

我想了一下
关于逆向模式串长度非法只能使用
^$
^.$
^..$
^...$
^....$
^.....$
^......$
^.......$
^..........*$

结合其他逆向的模式
组建非法日期的模式串
[^0-9]
^[3-9]
00..$
1[3-9]..$
[2-9]...$
00$     
3[2-9]$
[4-9].$
0[469]31$
1131$
0230$
0229$

以上不考虑闰年计算的
考虑闰年需要将最后一条替换成
[13579]0229$
[13579][048]0229$
[02468][26]0229$
[13579]000229$
[13579][048]000229$
[02468][26]000229$
天的白色影子

TOP

本帖最后由 batman 于 2011-5-30 19:52 编辑

期待qzw完整代码的出现,先贴出本人的愚解:
@echo off
:lp
cls&set "flag="&set "str="
set /p str=请输入:
set /a "p=!(%str:~,4%%%4)&!(!(%str:~,4%%%100))|!(%str:~,4%%%400)+8">nul 2>nul
echo %str%|findstr /x "[1-2][0-9][0-9][0-9]0[1-9]0[1-9] [1-2][0-9][0-9][0-9]1[0-2]0[1-9] [1-2][0-9][0-9][0-9]0[1-9]1[0-9] [1-2][0-9][0-9][0-9]1[0-2][1-2][0-9] [1-2][0-9][0-9][0-9]0[13456789]2[0-9] [1-2][0-9][0-9][0-9]022[0-%p%] [1-2][0-9][0-9][0-9]0[13578]3[0-1] [1-2][0-9][0-9][0-9]0[469]30 [1-2][0-9][0-9][0-9]1[02]3[0-1] [1-2][0-9][0-9][0-9]1130 30000[1-9]0[1-9] 30001[0-2]0[1-9] 30000[1-9]1[0-9] 30001[0-2][1-2][0-9] 30000[13456789]2[0-9] 3000022[0-%p%] 30000[13578]3[0-1] 30000[469]30 30001[02]3[0-1] 30001130">nul||set "flag=不"
echo 这是%flag%合法的日期
pause>nul&goto lpCOPY
简要说明下思路如下:
    整体为正向匹配法,就是列出所有合法日期的组合。正则表达式本来就很长了,如果再加入对平闰年的组合,表达式将更长,所以在前面对平闰年进行了计算并设置了针对二月的日期变量。

    随后在正则中先将合法年份的判断分为两个部分,第一部分的正则是[1-2][0-9][0-9][0-9],第二部分的正则就是3000;然后再这两种情况下分别组合日期为[0]1-9,[1-2][0-9],3[0-1]的情况,并在其中加入对月份合法的正则判断以及各月份最大天数值的正则判断,重点对2月进行了判断,正则为022[0-%p%],具体的分项为[1-2][0-9][0-9][0-9]022[0-%p%]和3000022[0-%p%]。其中p值为set/a计算出来的,平年为8,闰年为9。

    至于字符串合法性判断,以及长度判断用一个/x参数就可以实现了。

    个人测试没有发现问题,欢迎大家测试并批评指导。
***共同提高***

TOP

本帖最后由 qzwqzw 于 2011-5-30 20:08 编辑

以下是正、逆模式的测试代码
请各位检阅
@echo off & setlocal
set 正模式=
set "正模式=%正模式% ^[1-2][0-9][0-9][0-9]0[1-9]0[1-9]$"
set "正模式=%正模式% ^[1-2][0-9][0-9][0-9]0[1-9]1[0-9]$"
set "正模式=%正模式% ^[1-2][0-9][0-9][0-9]0[^02]2[0-9]$"
set "正模式=%正模式% ^[1-2][0-9][0-9][0-9]022[0-8]$"
set "正模式=%正模式% ^[1-2][0-9][0-9][0-9]0[13578]3[0-1]$"
set "正模式=%正模式% ^[1-2][0-9][0-9][0-9]0[469]30$"
set "正模式=%正模式% ^[1-2][0-9][0-9][0-9]1[0-2]0[1-9]$"
set "正模式=%正模式% ^[1-2][0-9][0-9][0-9]1[0-2][12][0-9]$"
set "正模式=%正模式% ^[1-2][0-9][0-9][0-9]1[02]3[0-1]$"
set "正模式=%正模式% ^[1-2][0-9][0-9][0-9]1130$"
set "正模式=%正模式% ^[1-2][0-9][13579][26]0229$"
set "正模式=%正模式% ^[1-2][0-9][2468][048]0229$"
set "正模式=%正模式% ^[1-2][0-9][02468][48]0229$"
set "正模式=%正模式% ^[02468][048]000229$"
set "正模式=%正模式% ^[13579][26]000229$"
set 正模式
echo.
set 逆模式=
set "逆模式=%逆模式% ^$"
set "逆模式=%逆模式% ^.$"
set "逆模式=%逆模式% ^..$"
set "逆模式=%逆模式% ^...$"
set "逆模式=%逆模式% ^....$"
set "逆模式=%逆模式% ^.....$"
set "逆模式=%逆模式% ^......$"
set "逆模式=%逆模式% ^.......$"
set "逆模式=%逆模式% ^..........*$"
set "逆模式=%逆模式% [^0-9]"
set "逆模式=%逆模式% ^[3-9]"
set "逆模式=%逆模式% 00..$"
set "逆模式=%逆模式% 1[3-9]..$"
set "逆模式=%逆模式% [2-9]...$"
set "逆模式=%逆模式% 00$"
set "逆模式=%逆模式% 3[2-9]$"
set "逆模式=%逆模式% [4-9].$"
set "逆模式=%逆模式% 0[469]31$"
set "逆模式=%逆模式% 1131$"
set "逆模式=%逆模式% 0230$"
set "逆模式=%逆模式% [13579]0229$"
set "逆模式=%逆模式% [13579][048]0229$"
set "逆模式=%逆模式% [02468][26]0229$"
set "逆模式=%逆模式% [13579]000229$"
set "逆模式=%逆模式% [13579][048]000229$"
set "逆模式=%逆模式% [02468][26]000229$
set 逆模式
echo.
:loop
set /p 输入值=按yyyymmdd格式输入日期,输入Q退出:
if /i "%输入值%"=="q" goto :eof
rem 去除输入串前后的空格
for %%v in (%输入值%) do set 输入值=%%v
echo.%输入值%|findstr "%正模式%">nul && set 正结果=合法|| set 正结果=非法
echo 正模式匹配后:'%输入值%'是%正结果%的日期
echo.
echo.%输入值%|findstr "%逆模式%">nul && set 逆结果=非法|| set 逆结果=合法
echo 逆模式匹配后:'%输入值%'是%逆结果%的日期
echo.
goto :loopCOPY
1

评分人数

    • batman: 思路总是那么相似PB + 10
天的白色影子

TOP

33# qzwqzw
两种模式的判断,好!

但楼上是特意不判断3000年的吗?
***共同提高***

TOP

是的特意没有判断3000年
感觉没有什么意义
如果扩展的话
可以直接简单扩展到0000~9999

32楼的正则模式串
可以将10以上月份的10~29合并匹配

感觉/x没有办法适应逆模式下的非法长度判定
不可有何扩展的思路
天的白色影子

TOP

35# qzwqzw
多谢提醒,已合并。。。

对于逆向的多项匹配确实是不能用/x和/v,一时也无好的思路。。。
***共同提高***

TOP

修订了正模式中的非2月的20~29匹配模式
比如如下的值正模式判断出错
20010020

set "正模式=%正模式% ^[1-2][0-9][0-9][0-9]0[^2]2[0-9]$"
改为
set "正模式=%正模式% ^[1-2][0-9][0-9][0-9]0[^02]2[0-9]$"
天的白色影子

TOP

刚才思考了一下
使用单条set应该也可以实现日期的合法性检查
有兴趣的可以贴一下的自己的方案
要求与楼主的大致相同
只是除了变换一下命令主体
天的白色影子

TOP

38# qzwqzw


单条set不难,单条算式倒是比较麻烦,不过貌似也有捷径

TOP

贴一下单条set的方案
利用了很多Set/a的错误检测特性
_%输入值%=1%输入值%
::利用运算符不存在检测判断输入值是否全数字
1/(年/1000) 和 1/(3000/年)
::利用被0除错误检测输入值中的年份是否1000<=年<=3000
%输入值:~7%/(9/1%输入值:~8%)
::利用运算符不存在和被0除错误检测输入值长度是否等于8
诸如此类
@echo off & setlocal
:loop
set /p 输入值=按yyyymmdd格式输入日期,输入Q退出:
if /i "%输入值%"=="q" goto :eof
rem 去除输入串前后的空格
for %%v in (%输入值%) do set 输入值=%%v
2>nul set /a "_%输入值%=1%输入值%,%输入值:~7%/(9/1%输入值:~8%),年=1%输入值:~0,4%-10000,月=1%输入值:~4,2%-100,日=1%输入值:~6,2%-100,大月=!((月-1)*(月-3)*(月-5)*(月-7)*(月-8)*(月-10)*(月-12)),闰年=!(年%%4)&!(!(年%%100))|!(年%%400),1/((年/1000)*(3000/年)*(月/1)*(12/月)*(日/1)*(31/日)*(!(日/31)|大月)*(!(日/30)|(月-2))*(!(日/29)|(月-2)|闰年))"&&set 结果=合法||set 结果=非法
echo set/a检测'%输入值%'的结果:%结果%的日期
echo.
goto :loop
pauseCOPY
1

评分人数

天的白色影子

TOP

呵呵,学习了,这个好用

TOP

本帖最后由 hfg1977 于 2012-2-3 02:27 编辑
::======================= 利用findstr判断输入日期的合法性 1000~2999===========
@echo off
set "str="&set /p "str=请输入yyyymmdd: "
set "year=%str:~0,4%"
set /a "yp=!(year%%4)^!(year%%100)|!(year%%400)"
set "str=%yp%%str%"
echo %str%>con&echo %str%|findstr "\<[0-1][1-2][0-9][0-9][0-9][0][1-9][0-1][1-9]\> \<[0-1][1-2][0-9][0-9][0-9][0][1 3-9][1-2][0-9]\> \<[0-1][1-2][0-9][0-9][0-9][0][13578][3][0-1]\> \<[0-1][1-2][0-9][0-9][0-9][0][469][3][0]\> \<[0-1][1-2][0-9][0-9][0-9][1][0-2][0][1-9]\> \<[0-1][1-2][0-9][0-9][0-9][1][0-2][1-2][0-9]\> \<[0-1][1-2][0-9][0-9][0-9][1][02][3][0-1]\> \<[0-1][1-2][0-9][0-9][0-9][1][1][3][0]\> \<[0][1-2][0-9][0-9][0-9][0][2][2][0-8]\> \<[1][1-2][0-9][0-9][0-9][0][2][2][0-9]\>">nul&&echo 这是合法的日期||echo 这不是合法的日期
pause
::===================== end 判断日期合法性================================COPY
判断是否闰年 套用"batman "版主的公式.
“阿姐走了。。。可是。。。我。。。我愿意。”

TOP

本帖最后由 hfg1977 于 2012-2-3 02:27 编辑
说明:
1.第一位为闰平年标志位
2.set /a "yp=!(year%%4)^!(year%%100)|!(year%%400)"
该公式在batman版主的贴中学习到
3.枚举所有合法的日期:
[0-1][1-2][0-9][0-9][0-9]-[0][1-9]-[0-1][1-9]
[0-1][1-2][0-9][0-9][0-9]-[0][1 3-9]-[1-2][0-9]
[0-1][1-2][0-9][0-9][0-9]-[0][13578]-[3][0-1]
[0-1][1-2][0-9][0-9][0-9]-[0][469]-[3][0]
[0-1][1-2][0-9][0-9][0-9]-[1][0-2]-[0][1-9]
[0-1][1-2][0-9][0-9][0-9]-[1][0-2]-[1-2][0-9]
[0-1][1-2][0-9][0-9][0-9]-[1][02]-[3][0-1]
[0-1][1-2][0-9][0-9][0-9]-[1][1]-[3][0]
[0][1-2][0-9][0-9][0-9]-[0][2]-[2][0-8]
[1][1-2][0-9][0-9][0-9]-[0][2]-[2][0-9]COPY
“阿姐走了。。。可是。。。我。。。我愿意。”

TOP

回复 40# qzwqzw


    正好写过日期检查函数,也贴个单 set 方案。
函数体:
:ChechDate Date(YYYYMMDD)
::检查日期是否合法,合法时将改变 errorlevel 变量的值为 0,非法时为 1,参数格式错误时不作改变
setlocal disabledelayedexpansion
set/a"1/((date=%~1)/10000)" 2>nul||echo call :ChechDate Date(YYYYMMDD)&&exit/b
set/a"b=1,y=%date:~,-4%,m=1%date:~-4,2%-100,d=1%date:~-2%-100,test=!(y%%4|!(y%%100)*!!(y%%400))*!(m^2)+(m+m/8)%%2-2*!(m^2)+30,b=0/(test/d*!(m/13))" 2>nul&&echo Right||echo Wrong
exit/b%b%COPY
使用范例:
@echo off
echo 20111215
call CheckDate 20111215
echo   %%errorlevel%%=%errorlevel%
::一个正确的日期
echo;
echo 20110229
call CheckDate 20110229
echo   %%errorlevel%%=%errorlevel%
::一个错误的日期
echo;
echo 20120229
call CheckDate 20120229 >nul
if errorlevel 1 (echo 错误) else echo 正确
echo   可以用 if errorlevel 判断
::也可以用连接符进行正误判断并自定义操作
echo;
echo 20120100
call CheckDate 20120100 >nul&&echo 正确||echo 错误
echo   也可以用管道符判断正误
::也可以用连接符进行正误判断并自定义操作
pause>nulCOPY

TOP

回复 23# CrLf


发现好象没人提计划任务, 那我提一下
schtasks /create /TN faketask /TR "CMD /C" /SC ONCE /SD 2015/12/18 /ST 00:00 /F
成功: 成功创建计划任务 "faketask"。
ECHO %ERRORLEVEL%
0
schtasks /create /TN faketask /TR "CMD /C" /SC ONCE /SD 2015/12/41 /ST 00:00 /F
错误: 开始日期不正确。
ECHO %ERRORLEVEL%
-2147467259COPY

TOP

返回列表