用纯P一贯到底,还是应该先解决 ‘卡位和定界’,即检查输入长度是否=5,检查第三位是否为 /,检查定界符之外是否均为数字,其后再完成月值与日值的关联处理,否则会使处理逻辑复杂化...
另说》纯P内部数据处理也许只有字符串一种数据类型,因此以下三式返回值相同
if 09 lss 1 (@echo,1) else @echo,0
if "09" lss "1" (@echo,1) else @echo,0
if 0q lss 1 (@echo,1) else @echo,0
作者: qixiaobin0715 时间: 2024-8-21 12:43
回复 27# aloha20200628
确实还有bug:0101/11
思路有问题,需要重写。
作者: qixiaobin0715 时间: 2024-8-21 16:08
重写代码,部分参考或者说借鉴27楼的思路,先按正确的格式定义月份日期,再进行判断:- @echo off
- for /l %%i in (1,1,31) do (
- if %%i lss 10 (
- set @0%%i=1
- set #0%%i=1
- ) else (
- set @%%i=1
- if %%i leq 12 set #%%i=1
- )
- )
- :o
- set/p "md=Please Input the Date (MM/DD):"
- if not "%md://=%"=="%md%" goto :p
- for /f "tokens=1* delims=/" %%i in ("%md%") do (
- if defined #%%i if defined @%%j set n=1
- if defined n (
- if "%%i" equ "02" (
- if "%%j" geq "30" set n=
- ) else (
- for %%k in (04 06 09 11) do if "%%i" equ "%%k" if "%%j" equ "31" set n=
- )
- )
- )
- :p
- if not defined n echo,Input Error&goto :o
- echo,Input Correct
- pause
复制代码
作者: qixiaobin0715 时间: 2024-8-21 16:20
本帖最后由 qixiaobin0715 于 2024-8-21 16:22 编辑
代码第13行是为了过滤类似这样的输入合法通过:01//01
如果觉得无所谓,去掉也行。
越搞越复杂。
就当练手吧。
作者: 77七 时间: 2024-8-21 16:25
回复 30# qixiaobin0715
月份日期分开定义,再拆开判断,不如直接全定义 #01/01 ...#12/31,然后结束了...
作者: qixiaobin0715 时间: 2024-8-21 16:28
本帖最后由 qixiaobin0715 于 2024-8-21 16:29 编辑
回复 31# 77七
想过,代码会缩减很多。但变量定义过多(至少366个),会影响效率。
上面说过了,主要是练练手。
作者: WHY 时间: 2024-8-21 21:16
本帖最后由 WHY 于 2024-8-21 21:25 编辑
回复 29# qixiaobin0715
还要考虑一下,分隔符位于字符串开头的情况, for /f 会去掉字符串开头的分隔符。
比如输入:/03/12
作者: WHY 时间: 2024-8-21 21:17
个人观点:特殊字符是 CMD 的硬伤,用纯P来解此题,简直就是自找麻烦。
吐槽一下:“你认为有前途的,其他人或许认为就是辣鸡”,事实证明这句话是对的。
作者: buyiyang 时间: 2024-8-21 21:27
才5个字符,用批处理的话逐字符判断更可靠一些- @echo off
- set/p "data=Please enter a date (MM/DD):"
- set "error=echo,Invalid date&pause&goto :eof"
- setlocal enabledelayedexpansion
- for /l %%i in (5,-1,0) do (
- set "data%%i=!data:~%%i,1!"
- if not "!data%%i!"=="" (
- if %%i equ 5 (
- %error%
- ) else if %%i equ 2 (
- if "!data%%i!" neq "/" %error%
- ) else if "!data%%i!" lss "0" (
- %error%
- ) else if "!data%%i!" gtr "9" %error%
- ) else (
- if %%i equ 4 %error%
- )
- )
- if %data0% equ 0 set "data0="
- if %data3% equ 0 set "data3="
- set mm=%data0%%data1%
- set dd=%data3%%data4%
- if %mm% gtr 12 %error%
- if %dd% gtr 31 %error%
- for /f "tokens=2" %%i in ('wmic os get codeset^,localdatetime') do (
- set yyyy=%%i
- set "yyyy=!yyyy:~0,4!"
- )
- endlocal&set /a mm=%mm%,dd=%dd%,yyyy=%yyyy%
- set /a "gtm=!(mm-4)|!(mm-6)|!(mm-9)|!(mm-11)","leap=!(yyyy%%4)&!!(yyyy%%100)|!(yyyy%%400)","dlim=!(mm-2)*(28+leap)+gtm*30+(!!(mm-2)&!gtm)*31"
- if %dd% gtr %dlim% (%error%) else (echo,Valid date)
- pause&exit /b
复制代码
作者: buyiyang 时间: 2024-8-21 21:32
回复 27# aloha20200628
因为09不是有效的八进制数字,试试0x9
作者: 77七 时间: 2024-8-22 08:34
回复 35# buyiyang
大佬,00/00的情况,没有判断,防不胜防
作者: qixiaobin0715 时间: 2024-8-22 09:04
本帖最后由 qixiaobin0715 于 2024-8-22 09:07 编辑
回复 34# WHY
我也知道这么一个问题,用cmd搞出如此复杂的代码,确实不合适。
开始看到这个帖子,主要是想籍此私下练习练习逻辑思维,等到着手写代码时,没想到会是这么复杂,自己心里没底,发出来让大家看看 ,真是漏洞百出,最后重写代码,还是有漏洞。
最后的代码是借鉴27楼的建议重写的,发上来前,在13行下面有一行代码,是用来判断第3个字符是否为“/”的,个人感觉后续代码能够处理此问题,就给删除了,看来还是有用的,最少能够修补你在33楼所说的漏洞。
还是要在29楼第13、14行之间,加上删除的那行代码:- if not "%md:~2,1%"=="/" goto :p
复制代码
作者: qixiaobin0715 时间: 2024-8-22 10:48
回复 31# 77七
私下试了一把,全定义确实省事。
作者: 77七 时间: 2024-8-22 11:11
用临时文件,仅判断两位数+/+两位数,应该可以对付所有特殊字符了吧
- @echo off
- set /p str=input:
- setlocal enabledelayedexpansion
- >1.txt echo=#!str!
- endlocal
- findstr /rxc:"#[0-9][0-9]/[0-9][0-9]" 1.txt
- if not errorlevel 1 (
- echo ok
- )
- pause
复制代码
作者: aloha20200628 时间: 2024-8-22 11:15
本帖最后由 aloha20200628 于 2024-8-22 11:19 编辑
即便是批处这类简单脚本级的造码,也是讲究 ‘有效 》可靠 》高效 》简洁’ 四重关,新手过头关,老手要高攀,若每次出手都能 ‘会当凌绝顶’,真可谓功德圆满了... 共勉共勉
作者: qixiaobin0715 时间: 2024-8-22 12:46
本帖最后由 qixiaobin0715 于 2024-8-22 12:48 编辑
仔细的研究了findstr命令的一般表达式,确实功能极其有限,相当于极简版的正则。有点手痒痒,也来一个吧。匹配原则:先多后少,先一般后特殊。- findstr /x "0[1-9]/[0-2][1-9] 1[0-2]/[0-2][1-9] 0[1-9]/[12]0 1[0-2]/[12]0 0[13-9]/30 1[0-2]/30 0[13578]/31 1[02]/31"
复制代码
表达式说明:
0[1-9]/[0-2][1-9] —— 1、2组对应所有月份,日期在30以内的组合,不包括日期10、20、30,因为不易避开非法日期00,还是单独处理为好;
1[0-2]/[0-2][1-9]
0[1-9]/[12]0 —— 3、4组单独处理上面所说的未包括的日期10、20,也是对应所有月份;
1[0-2]/[12]0
0[13-9]/30 —— 5、6组对应日期为30的月份,2月除外;
1[0-2]/30
0[13578]/31 —— 最后2组对应日期为31的月份,包括1、3、5、7、8、10、12月;
1[02]/31
欢迎大家批评指正。
作者: buyiyang 时间: 2024-8-22 13:04
回复 37# 77七
感谢测试,限制上限的时候忘记限制下限了,再补上 set /a "1/(!!mm&!!dd)" 2>nul ||(%error%) 就没有问题了。
作者: qixiaobin0715 时间: 2024-8-24 09:54
回复 36# buyiyang
细致!严谨!
作者: aloha20200628 时间: 2024-8-24 13:57
本帖最后由 aloha20200628 于 2024-8-24 23:07 编辑
再练一把 ‘纯P进行到底’ 的脑力操...
给一个纯P版本的日期输入合法性检查代码,不用外部方法,不用正则匹配
算法简明得益于采用 ‘字典变量’,尽可能考虑了各种防错对策》分隔符及其错位,日月数值溢出,日月相关,平闰年天数区分... 还是回归日月均为两位数的要求。
以下代码采用循环输入以便完成各种测试,直至空回车退出...
- @echo off &setlocal
- set/a "_1=31,_2=28,_3=31,_4=30,_5=31,_6=30,_7=31,_8=31,_9=30,_10=31,_11=30,_12=31,y=%date:~,4%%%4"
- if %y% equ 0 set "_2=29"
- :[md_loop]
- set "md=" &set "c=" &set/p "md=输入日期(月值/日值):"
- if not defined md endlocal&exit/b
- setlocal enabledelayedexpansion &set k=!md:"=!
- if "!k!" neq "!md!" echo,非法&endlocal&goto[md_loop]
- endlocal &if "%md:~5%" neq "" echo,非法&goto[md_loop]
- if "%md:~4,1%"=="" echo,非法&goto[md_loop]
- for /f "tokens=1,2 delims=/" %%1 in ("%md%") do set "m=%%1"&set "d=%%2"
- if "%md%"=="%m%" echo,非法&goto[md_loop]
- for /f "delims=0123456789" %%n in ("%m%%d%") do set "c=1"
- if defined c echo,非法&goto[md_loop]
- if not defined d echo,非法&goto[md_loop]
- if "%md:~2,1%" neq "/" echo,非法&goto[md_loop]
- if "%m:~0,1%" equ "0" if "%m:~1,1%" neq "" set "m=%m:~1%"
- set "_m=_%m%" &set "w=非法" &setlocal enabledelayedexpansion
- if "%d:~0,1%" equ "0" if "%d:~1,1%" neq "" set "d=%d:~1%"
- if %d% gtr 0 if %d% leq !%_m%! set "w=合法"
- echo,!w!&endlocal&goto[md_loop]
复制代码
作者: buyiyang 时间: 2024-8-24 17:13
本帖最后由 buyiyang 于 2024-8-24 17:47 编辑
回复 45# aloha20200628
1//1a
1/--1
1/+1
一个是分隔符被忽略的问题,一个是if比较时不能转换成有效数字的会按字符比较,数字比较时没有排除正负号。
忘了还有变量延迟下的两个特殊字符,
1/!1
1/!^1
作者: 77七 时间: 2024-8-24 18:20
本帖最后由 77七 于 2024-8-24 18:29 编辑
- @echo off
- for /f %%a in ('wmic os get localdatetime ^|findstr [0-9]') do set year=%%a&call set year=%%year:~0,4%%
- set /a _1=_3=_5=_7=_8=_10=_12=31,_4=_6=_9=_11=30
- set/a num=!(year%%4) ^& !(!(year%%100)) ^| !(year%%400),1/num 2>nul && set _2=29|| set _2=28
-
- :loop
- setlocal
- set /p n=input:
- set "n1=%n:~0,2%"
- set "n2=%n:~2,1%"
- set "n3=%n:~3,2%"
- set "n4=%n:~5%"
- setlocal enabledelayedexpansion
- set a=非法
- if "!n2!" equ "/" (
- if "!n4!" equ "" (
- for /l %%l in (1,1,12) do (
- set str=0%%l
- if "!n1!" equ "!str:~-2!" (
- for /l %%m in (1,1,!_%%l!) do (
- set str=0%%m
- if "!n3!" equ "!str:~-2!" (
- set a=合法
- )
- )
- )
- )
- )
- )
- endlocal & endlocal &echo %a%
- goto :loop
复制代码
判断 相应位置的字符串与 分隔符号 "/" 及限定范围的日期、月份是否有相等情况。初步测试,可以应付各种特殊字符。
作者: 77七 时间: 2024-8-24 18:53
简化一下- @echo off
- for /f %%a in ('wmic os get localdatetime ^|findstr [0-9]') do set year=%%a&call set year=%%year:~0,4%%
- set /a _1=_3=_5=_7=_8=_10=_12=31,_4=_6=_9=_11=30
- set/a num=!(year%%4) ^& !(!(year%%100)) ^| !(year%%400),1/num 2>nul && set _2=29|| set _2=28
-
- :loop
- setlocal
- set /p n=input:
- setlocal enabledelayedexpansion
- set a=非法
- if "!n:~2,1!!n:~5,1!" equ "/" (
- for /l %%l in (1,1,12) do (
- set str=0%%l
- if "!n:~0,2!" equ "!str:~-2!" (
- for /l %%m in (1,1,!_%%l!) do (
- set str=0%%m
- if "!n:~3,2!" equ "!str:~-2!" (
- set a=合法
- )
- )
- )
- )
- )
- endlocal & endlocal &echo %a%
- goto :loop
复制代码
作者: aloha20200628 时间: 2024-8-24 19:09
本帖最后由 aloha20200628 于 2024-8-24 19:46 编辑
回复 46# buyiyang
45楼代码已订正,堵上了被多种 ‘怪异字符’ 轰击破防的缺口...
本帖歇后语》不用外部方法援助,不用正则匹配简化,感觉纯P自力更生的造码能力还可以...而真正的着力点落在了应对预处理和防止怪异字符的雷劈...
作者: buyiyang 时间: 2024-8-24 19:44
回复 45# aloha20200628
endlcoal 后第二行设定的变量也无了,
第14行的if %m% lss 1 if %m% gtr 12 逻辑有误,其实这一行不要也行,第17行if %d% gtr 0 if %d% leq !%_m%! 兼有限制月份的作用。
作者: aloha20200628 时间: 2024-8-24 20:52
本帖最后由 aloha20200628 于 2024-8-24 21:02 编辑
回复 50# buyiyang
谢谢细心测试 45楼代码已被订正...
要纯P到底,那些 卡位,定界,全数字核查... 一点懒儿都不能偷
作者: buyiyang 时间: 2024-8-24 21:11
本帖最后由 buyiyang 于 2024-8-25 12:47 编辑
综合一下35、45、48、55楼,有一些不错的写法
最终主体只需要9、11、12行三句判断就够了。
第9行限制输入字符数和分隔符位置,
第11行限制月份和日期均为数字,
第12行限制月份和日期范围。- @echo off
- for /f "tokens=2" %%i in ('wmic os get codeset^,localdatetime') do set yyyy=%%i&call set yyyy=%%yyyy:~0,4%%
- set /a _01=_03=_05=_07=_08=_10=_12=31,_04=_06=_09=_11=30,"_02=28+(!(yyyy%%4)&!!(yyyy%%100)|!(yyyy%%400))"
- set "error=echo,Invalid date&endlocal&goto :loop"
-
- :loop
- set /p "md=Please enter a date (MM/DD):"
- setlocal enabledelayedexpansion
- if "!md:~2,-2!" neq "/" (%error%)
- set "mm=!md:~0,2!"&set "dd=!md:~3,2!"
- for /f "delims=0123456789" %%i in ("!mm!!dd!") do (%error%)
- if "!dd!" gtr "00" if "!dd!" leq "!_%mm%!" (echo,Valid date&endlocal&goto :loop)
- %error%
复制代码
作者: 77七 时间: 2024-8-24 21:54
回复 45# aloha20200628
大佬,感觉应对特殊字符还是开启延迟变量扩展专业,如第7、8行无法处理 双引号
作者: aloha20200628 时间: 2024-8-24 23:11
本帖最后由 aloha20200628 于 2024-8-24 23:26 编辑
回复 53# 77七
谢谢 代码已订正... 但愿是最后一把 ‘堵漏灵’...
从8楼调用 powershell+findstr 外援的4-5行代码到45楼的纯P自力更生版,已经垒起21行代码了,要经得起各种怪异字符的 ‘雷劈’ ... 纯粹是要过把瘾的一套脑力操...
作者: qixiaobin0715 时间: 2024-8-25 10:03
本帖最后由 qixiaobin0715 于 2024-8-25 10:39 编辑
不包括修改代码,我也发上来过两版代码,就是漏洞太多。总体感觉是,不能自我陶醉,沾沾自喜,总是觉得自己的代码思路好,完美无缺,实际上还差得远着呢,低调最重要。
不怕大家笑话,再来一版,希望大佬们批评指正。还是限定输入格式为:01/01这样的。
下面代码的前一部分还是主要借鉴了27楼的思路。原则上尽量少预设变量(29楼代码开始预设了几十个变量,主要是便于后面进行判断,可能会影响一些效率)。第6行判断语句既定位了“/”字符,又能限定输入的字符长度为5,一举两得,主要还是得益于aloha20200628的提醒:- @echo off
- setlocal enabledelayedexpansion
- :o
- set/p "md=Please Input the Date (MM/DD):"
- set "mm/dd=!md!"
- if "!mm/dd:~2,-2!"=="/" (
- if "!mm/dd:00=!"=="!mm/dd!" (
- for /l %%i in (0,1,9) do set "mm/dd=!mm/dd:%%i=!"
- if "!mm/dd!"=="/" set n=1
- )
- )
- if not defined n goto :p
- for /f "tokens=1* delims=/" %%i in ("!md!") do (
- if %%i gtr 12 (set n=) else if %%j gtr 31 (set n=)
- if defined n (
- if %%j equ 30 (
- if %%i equ 2 set n=
- ) else if %%j equ 31 (
- for %%k in (02 04 06 09 11) do if %%k equ %%i set n=
- )
- )
- )
- :p
- if defined n (echo,Input Correct) else (echo,Input Error&goto :o)
- pause
复制代码
另外,改变一下输入格式。合法:1/2 1/31 01/02 01/31 12/01 12/1,非法:01/2 1/01。如何才能判断?
作者: 77七 时间: 2024-8-25 11:33
回复 55# qixiaobin0715
大佬,您最后提出的新问题,我没看懂...
作者: qixiaobin0715 时间: 2024-8-25 12:01
本帖最后由 qixiaobin0715 于 2024-8-25 12:03 编辑
回复 56# 77七
我的失误,没有表达清楚。有人习惯月份日期是个位数时前面加个0,都变成两位数;有人不习惯加0补位,直接写。我要表达的是,两种不能混合写,比如1月1日,要么写成01/01或者1/1,而不能写成01/1或1/01。
作者: 77七 时间: 2024-8-25 12:08
回复 55# qixiaobin0715
大佬,我觉得几十个变量不会影响效率。尤其类似的简短变量 set #01=01,试着定义了5000个,耗时1秒左右,然后判断是否定义,echo %time%对比了下,时间相同。- 12:07:14.02
- 12:07:15.26
- 1
- 12:07:15.26
复制代码
分别为定义开始时间、结束时间、判断是否被定义时间
作者: buyiyang 时间: 2024-8-25 12:26
本帖最后由 buyiyang 于 2024-8-25 12:32 编辑
回复 55# qixiaobin0715
我尝试写了一个- @echo off
- for /f "tokens=2" %%i in ('wmic os get codeset^,localdatetime') do set yyyy=%%i&call set yyyy=%%yyyy:~0,4%%
- set /a _01=_03=_05=_07=_08=_10=_12=31,_04=_06=_09=_11=30,"_02=28+(!(yyyy%%4)&!!(yyyy%%100)|!(yyyy%%400))"
- set "error=echo,Invalid date&endlocal&goto :loop"
-
- :loop
- set /p "md=Please enter a date (M/D):"
- setlocal enabledelayedexpansion
- set "a=!md:*/=!"&set "dd=!a:/=!"
- if "!a!" neq "!dd!" (%error%)
- for /f "delims=0123456789" %%i in ("!md:/=!") do (%error%)
- for /f "tokens=1* delims=/" %%i in ("!md!") do (endlocal&set "mm=%%i"&set "dd=%%j")
- setlocal enabledelayedexpansion
- if "!dd!"=="" (%error%)
- if "!mm:~2,1!" neq "" (%error%)
- if "!dd:~2,1!" neq "" (%error%)
- if "!mm:~0,1!" equ "0" if "!dd:~1,1!"=="" (%error%)
- if "!dd:~0,1!" equ "0" if "!mm:~1,1!"=="" (%error%)
- set "mm=0!mm!"&set "mm=!mm:~-2!"
- set "dd=0!dd!"&set "dd=!dd:~-2!"
- if "!dd!" gtr "00" if "!dd!" leq "!_%mm%!" (echo,Valid date&endlocal&goto :loop)
- %error%
复制代码
作者: aloha20200628 时间: 2024-8-25 15:50
本帖最后由 aloha20200628 于 2024-8-25 16:18 编辑
精简了45楼代码中的操作步骤和合法性核查逻辑,行数减至18行,8个goto减至2个...
操作步骤要点》
双引号排查
输入长度排查
定界符及其错位排查
日月值全数字排查
日月相关变化所对应的字典变量 以及 平闰年天数增减修正
全程严防 &!"^ 等特殊字符雷劈的对策...
再次感谢各位细心测试反馈 就算是一场把纯P贯彻到底的基本功组合复习吧...
- @echo off &setlocal
- set/a "_1=31,_2=28,_3=31,_4=30,_5=31,_6=30,_7=31,_8=31,_9=30,_10=31,_11=30,_12=31,y=%date:~,4%%%4"
- if %y% equ 0 set "_2=29"
- :[md_loop]
- set "$md=" &set "c=" &set/p "$md=输入日期(月值/日值):"
- if not defined $md endlocal&exit/b
- setlocal enabledelayedexpansion &set #md=!$md:"=!
- if "!#md!"=="!$md!" if "!$md:~5!"=="" if "!$md:~4,1!" neq "" if "!$md:~2,1!"=="/" (
- set "m=!$md:~0,2!"&set "d=!$md:~3!"
- for /f "delims=0123456789/" %%n in ("!$md!") do set "c=1"
- if not defined c goto[ok] )
- echo,非法&endlocal&goto[md_loop]
- :[ok]
- if "!m:~0,1!" equ "0" set "m=!m:~1!"
- set "_m=_!m!" &set "w=非法"
- if "!d:~0,1!" equ "0" set "d=!d:~1!"
- if !d! gtr 0 if !d! leq !%_m%! set "w=合法"
- echo,!w!&endlocal&goto[md_loop]
复制代码
作者: qixiaobin0715 时间: 2024-8-26 08:21
回复 58# 77七
是的,这里只是对1个数据进行判断,不考虑效率没问题,像你先前所说的全定义更简单。
作者: qixiaobin0715 时间: 2024-8-26 14:34
回复 58# 77七
实际上不喜欢为了让别人看起来自己写的代码行数较少,而强行将多行变成一行,比较喜欢你的风格,虽然从行数上看代码较长,但是一目了然,清清楚楚,最近我好像也有点给带偏了。
给自己代码较长强行找点理由。既然对于这个问题来说,效率不是那么重要,就来个数据全定义代码,这样子判断起来就简单多了,要是有空的话,帮忙测试一下耗时情况:- @echo off
- for /l %%i in (1,1,12) do (
- for /l %%j in (1,1,31) do (
- if %%i lss 10 (
- if %%j lss 10 (
- set _"%%i/%%j"=0
- set _"0%%i/0%%j"=0
- ) else (
- set _"%%i/%%j"=0
- set _"0%%i/%%j"=0
- )
- ) else (
- if %%j lss 10 (
- set _"%%i/%%j"=0
- set _"%%i/0%%j"=0
- ) else (
- set _"%%i/%%j"=0
- )
- )
- )
- )
- for %%i in (2 4 6 9) do (
- set _"%%i/31"=
- set _"0%%i/31"=
- )
- set _"11/31"=
- set _"2/30"=
- set _"02/30"=
- setlocal enabledelayedexpansion
- :o
- set/p "md=Please Input the Date (MM/DD):"
- if defined _"!md!" (
- echo,Input Correct
- ) else (
- echo,Input Error
- goto :o
- )
- pause
复制代码
作者: 77七 时间: 2024-8-26 15:45
回复 62# qixiaobin0715
感谢大佬认可!我觉得代码发出来交流,如果写的紧凑到一起,至少我是不想读的。
用echo %time%简单测试了一轮,全部写明日期。
52楼(去除了获取年份及判断平闰年代码)耗时0.01秒
60楼 耗时0.01秒
62楼 耗时0.13秒
在本题实际应用环境下,感觉没必要考虑效率,毕竟打开批处理,就已经 “预处理” 完成了。
如果判断大量数据,猜测全定义效率最高,毕竟只要一个 if defined:lol
作者: qixiaobin0715 时间: 2024-8-26 16:12
回复 63# 77七
不好说,毕竟每次执行defined时都要从大量的预定义的变量中查找符合条件的变量。
作者: 77七 时间: 2024-8-26 16:27
回复 64# qixiaobin0715
大佬,我测试了下
1.txt 为1-10000,共1万个数字用for /f 判断
- 16:25:16.03
- 16:25:16.15
- 16:25:16.20
复制代码
定义用了0.12秒,判断是否定义仅用了0.05秒
作者: qixiaobin0715 时间: 2024-8-26 16:40
回复 65# 77七
还是相信测试吧。
作者: aloha20200628 时间: 2024-8-26 16:49
批处是一种典型的解译型脚本,其执行原理基本上就是逐行处理(连注释行也不放过),也许对复合语块要先全块读尽再逐行处理,因此代码能并为一行会比分行的解译执行效率高,此被老帖早有述及,但这同时也会降低代码可读性... 总而言之,这是一个二者权衡尺度的问题,又是一个造码者编程风格或言个人偏好的问题...
作者: 77七 时间: 2024-8-26 17:22
回复 67# aloha20200628
大佬,我使用set /a 测试了一下
- @echo off
- for /l %%l in (1,1,5) do (
- timeout 3 >nul
- setlocal
- echo 紧凑型
- call echo %%time%%
- call :1
- call echo %%time%%
- endlocal
- echo=
- timeout 3 >nul
- setlocal
- echo 分散型
- call echo %%time%%
- call :2
- call echo %%time%%
- endlocal
- echo=
- )
- pause
- exit
-
- :1
- for /l %%l in (1,1,10000) do (
- set /a a=1&set /a b=2&set /a c=3&set /a d=4&set /a e=5&set /a f=6&set /a g=7
- )
- exit /b
- :2
- for /l %%l in (1,1,10000) do (
- set /a a=1
- set /a b=2
- set /a c=3
- set /a d=4
- set /a e=5
- set /a f=6
- set /a g=7
- )
- exit /b
复制代码
- 紧凑型
- 17:15:34.13
- 17:15:38.26
-
- 分散型
- 17:15:41.12
- 17:15:45.01
-
- 紧凑型
- 17:15:48.19
- 17:15:52.18
-
- 分散型
- 17:15:55.16
- 17:15:59.17
-
- 紧凑型
- 17:16:02.14
- 17:16:06.23
-
- 分散型
- 17:16:09.20
- 17:16:13.18
-
- 紧凑型
- 17:16:16.18
- 17:16:20.20
-
- 分散型
- 17:16:23.16
- 17:16:27.09
-
- 紧凑型
- 17:16:30.16
- 17:16:34.17
-
- 分散型
- 17:16:37.16
- 17:16:41.06
-
- 请按任意键继续. . .
复制代码
用&连接,效率反而要低些
作者: aloha20200628 时间: 2024-8-26 18:16
本帖最后由 aloha20200628 于 2024-8-26 18:30 编辑
回复 68# 77七
已说过也许批处对复合语块典型如for...句式是先全块读尽处理的,此乃for句式效率较高的原因,其内是不能如其外简单分行执行的...
与解译型脚本逐行解译执行原理一致的纯净测试应该如是:
set a=...&set b=...&...
和
set a=...
set b=...
...
比对测试
但对批处的小微代码测试而言,其差别也许无感...
作者: qixiaobin0715 时间: 2024-8-26 18:48
回复 68# 77七
那就用goto循环语句测试一下试试。
作者: 77七 时间: 2024-8-26 18:52
回复 69# aloha20200628
简单测试了下,果然如大佬所言,call 了100次,&连接的耗时0.22秒,分开写的耗时0.36秒。
作者: 77七 时间: 2024-8-26 18:57
回复 70# qixiaobin0715
goto测试,100次,&连接耗时0.23秒,分开写 0.40秒
作者: qixiaobin0715 时间: 2024-8-26 19:08
回复 72# 77七
谢谢测试,对此种效率有了更进一步的了解。
作者: WHY 时间: 2024-8-27 22:58
本帖最后由 WHY 于 2024-8-28 08:53 编辑
回复 68# 77七
用 & 连接的语句,本身就是语句块;放到 for 循环里,语句块里面再套语句块,预处理时 cmd 认为是等价的,预处理花费的时间是一样的,执行时间相差无几。
就是说,- for %%i in (1) do (
- set "a=1"
- set "b=2"
- set "c=3"
- )
复制代码
与- for %%i in (1) do set "a=1" & set "b=2" & set "c=3"
复制代码
以及- for %%i in (1) do (
- set "a=1" & set "b=2" & set "c=3"
- )
复制代码
等价
参考:http://www.bathome.net/thread-4482-1-1.html
PS: 想要提速,多在算法和思路上做文章,尽量少用call和goto;尽量少在for循环体内部使用外部命令。。。
用 & 、&&、||连接虽然可以带来效率提升,但提升空间非常有限,反倒是可读性、可维护性大打折扣,能不用就坚决不用吧。
作者: 77七 时间: 2024-8-28 00:39
回复 74# WHY
谢谢大佬指点!
欢迎光临 批处理之家 (http://bbs.bathome.net/) |
Powered by Discuz! 7.2 |