标题: [ 新手练习 4 ] 批处理计算字符串长度 [打印本页]
作者: wxcute 时间: 2008-11-28 20:28 标题: [ 新手练习 4 ] 批处理计算字符串长度
假定一字符串 “123ABC上中下”,计算出这个字符串的长度,即有几个字符。
目的:掌握变量截取与条件判断用法。
要求:让批处理自动计算出字符串的长度。字符串可自定义,暂不考虑特殊字符。
评分:代码可读性 1 分;
首个新方法 6 分,第二个 5 分,依次类推,最少 2 分;
一人可多种方法,新方法追加 3 分,已经出现过的方法追加 1 分。
作者: BBCC 时间: 2008-11-29 13:25
- @echo off&setlocal EnableDelayedExpansion
- set "var=1234567890 1 $"
- :loop
- set /a a+=1
- if not "!var:~%a%,1!" equ "" (goto :loop) else (echo %var%&echo. %a%&pause)
复制代码
效率极为低下.
作者: lhjoanna 时间: 2008-11-29 20:13
对上述的两种方法进行了稍许改进,并且自己新加了一种方法,并加以比较运行效率。得出对于1000个字符的(似乎最长也只能处理长度为1000左右的字符串)长度计算,三楼方法(改进后)比二楼快约500毫秒,新方法(法三)效率与二楼相当,是在我的机子上。所以如果求的字符串数量很多的话(如成千上万个),还是用第二种方法较好!
测试字符串生成可以用如下命令 @set /p=%random%<nul >>a.txt&%0
新加了法四,batman的高见!
- @echo off&setlocal enabledelayedexpansion
- set /p "var=请输入字符串:"
- echo ========================
- echo [法一]
- set time1=%time%
- set /a time1_second=1%time1:~-5,2%-100
- set /a time1_millisec=1%time1:~-2,2%-100
- rem ----------[法一]主程序开始---------------------
- :loop
- set /a a+=1
- if not "!var:~%a%,1!" equ "" goto :loop
- echo 共有%a%个字符
- rem ----------[法一]主程序结束---------------------
- set time2=%time%
- set /a time2_second=1%time2:~-5,2%-100
- set /a time2_millisec=1%time2:~-2,2%-100
- if %time2_millisec% lss %time1_millisec% set /a time2_millisec+=100&set /a time2_second-=1
- set /a second=time2_second-time1_second
- set /a millisec=time2_millisec-time1_millisec
- echo 开始时间:%time1% 结束时间:%time2%
- echo 程序1运行时间为%second%秒%millisec%0毫秒
- echo ========================
- echo [法二]
- set time1=%time%
- set /a time1_second=1%time1:~-5,2%-100
- set /a time1_millisec=1%time1:~-2,2%-100
- rem ----------[法二]主程序开始---------------------
- for /l %%a in (0,1,10000) do if "!var:~%%a,1!" equ "" set length=%%a&goto end
- :end
- echo 共有%length%个字符
- rem ----------[法二]主程序结束---------------------
- set time2=%time%
- set /a time2_second=1%time2:~-5,2%-100
- set /a time2_millisec=1%time2:~-2,2%-100
- if %time2_millisec% lss %time1_millisec% set /a time2_millisec+=100&set /a time2_second-=1
- set /a second=time2_second-time1_second
- set /a millisec=time2_millisec-time1_millisec
- echo 开始时间:%time1% 结束时间:%time2%
- echo 程序2运行时间为%second%秒%millisec%0毫秒
- echo ========================
- echo [法三]
- set time1=%time%
- set /a time1_second=1%time1:~-5,2%-100
- set /a time1_millisec=1%time1:~-2,2%-100
- rem ----------[法三]主程序开始---------------------
- set count=0
- :loop2
- set /a num+=1
- for /f %%i in ("%num%") do if not "!var:~%%i,1!"=="" goto loop2
- echo 共有%num%个字符
- rem ----------[法三]主程序结束---------------------
- set time2=%time%
- set /a time2_second=1%time2:~-5,2%-100
- set /a time2_millisec=1%time2:~-2,2%-100
- if %time2_millisec% lss %time1_millisec% set /a time2_millisec+=100&set /a time2_second-=1
- set /a second=time2_second-time1_second
- set /a millisec=time2_millisec-time1_millisec
- echo 开始时间:%time1% 结束时间:%time2%
- echo 程序3运行时间为%second%秒%millisec%0毫秒
- echo ========================
- echo [法四] batman's idea
- set time1=%time%
- set /a time1_second=1%time1:~-5,2%-100
- set /a time1_millisec=1%time1:~-2,2%-100
- rem ----------[法四]主程序开始---------------------
- echo %var%>a.txt
- echo.>>a.txt
- for /f "tokens=1 delims=:" %%i in ('findstr /o .* a.txt') do set /a length=%%i-2&if not %%i
- equ 0 echo 共有%length%个字符&goto end
- :end
- del a.txt
- rem ----------[法四]主程序结束---------------------
- set time2=%time%
- set /a time2_second=1%time2:~-5,2%-100
- set /a time2_millisec=1%time2:~-2,2%-100
- if %time2_millisec% lss %time1_millisec% set /a time2_millisec+=100&set /a time2_second-=1
- set /a second=time2_second-time1_second
- set /a millisec=time2_millisec-time1_millisec
- echo 开始时间:%time1% 结束时间:%time2%
- echo 程序4运行时间为%second%秒%millisec%0毫秒
- pause>nul
复制代码
刚有些小问题,已修改,大家运行看看!!!
[ 本帖最后由 lhjoanna 于 2008-11-29 21:46 编辑 ]
作者: batman 时间: 2008-11-29 21:26
大家可以想想怎么利用findstr /o去实现吧
作者: lhjoanna 时间: 2008-11-29 21:44
batman的方法果然很好啊,我一直都没有注意到也没有用过参数/o,每一个参数都有存在的价值啊,佩服!刚写出来运行了一下看(不知代码够不够简洁),效率与[法二]相当。很值得推荐啊!在4楼更新了一下!
[ 本帖最后由 lhjoanna 于 2008-11-29 21:46 编辑 ]
作者: BBCC 时间: 2008-11-29 21:55
[法一]
共有1234568个字符
开始时间:21:54:45.96 结束时间:21:54:45.96
程序1运行时间为0秒00毫秒
========================
[法二]
共有10个字符
开始时间:21:54:45.96 结束时间:21:54:46.05
程序2运行时间为0秒90毫秒
========================
[法三]
共有10个字符
开始时间:21:54:46.05 结束时间:21:54:46.07
程序3运行时间为0秒20毫秒
========================
[法四] batman's idea
命令语法不正确。
有点问题哦
作者: lhjoanna 时间: 2008-11-29 21:58
我这里可以啊,你再运行看看??- ========================
- [法一]
- 共有1021个字符
- 开始时间:21:57:20.33 结束时间:21:57:21.52
- 程序1运行时间为1秒190毫秒
- ========================
- [法二]
- 共有1021个字符
- 开始时间:21:57:21.52 结束时间:21:57:21.70
- 程序2运行时间为0秒180毫秒
- ========================
- [法三]
- 共有1021个字符
- 开始时间:21:57:21.70 结束时间:21:57:23.00
- 程序3运行时间为1秒300毫秒
- ========================
- [法四] batman's idea
- 共有1021个字符
- 开始时间:21:57:23.00 结束时间:21:57:23.21
- 程序4运行时间为0秒210毫秒
复制代码
经过测试发现[法一]与[法三]在字符数很少时,比如100个以内时会比[法二]和[法四]小,字符数很多时会增到1秒以上,而[法二]和[法四]总是维持在150-250毫秒之间。算法的好坏判断是运行时间(效率)不随测试数据的变化而大幅波动,总是稳定在一定的范围内。所以在求字符串长度中,[法二]与[法四]可以算较好的算法。
[ 本帖最后由 lhjoanna 于 2008-11-29 22:07 编辑 ]
作者: BBCC 时间: 2008-11-29 22:03
这次就行了- [法一]
- 共有83个字符
- 开始时间:22:02:01.70 结束时间:22:02:01.75
- 程序1运行时间为0秒50毫秒
- ========================
- [法二]
- 共有83个字符
- 开始时间:22:02:01.77 结束时间:22:02:01.85
- 程序2运行时间为0秒80毫秒
- ========================
- [法三]
- 共有83个字符
- 开始时间:22:02:01.85 结束时间:22:02:01.91
- 程序3运行时间为0秒60毫秒
- ========================
- [法四] batman's idea
- 共有83个字符
- 开始时间:22:02:01.91 结束时间:22:02:01.95
- 程序4运行时间为0秒40毫秒
复制代码
还是batman的牛啊,越长越快捷,但是能够解释一下为什么会多2出来吗?
[ 本帖最后由 BBCC 于 2008-11-29 22:08 编辑 ]
作者: BBCC 时间: 2008-11-29 22:10
[法四]可以算较好的算法
findstr的牛逼用途导致有那么高的效率
作者: lhjoanna 时间: 2008-11-29 22:13
你用findstr /o对一个文本文件进行操作,看一下结果,把数字与冒号也算做偏移量,第二行显示的数字就是第一行字符的长度加上开始的数字与冒号,所以减2就是第一行的字符串长度了。我推测的,没有任何理论依据,还请高手来个权威的解释啊。
[ 本帖最后由 lhjoanna 于 2008-11-29 22:18 编辑 ]
作者: BBCC 时间: 2008-11-29 22:18
看了一下英语版的帮助,不明白
/O rints character offset before each matching line.
在每行之前显示偏移量?
[ 本帖最后由 BBCC 于 2008-11-29 22:20 编辑 ]
作者: batman 时间: 2008-11-29 22:42
关于findstr /o的用法,大家可以参照这个帖子:
http://www.bathome.net/viewthrea ... hlight=%C1%B7%CF%B0
作者: Batcher 时间: 2008-11-29 22:45 标题: 回复 11楼 的帖子
多出来的2个,并非冒号以及前面的数字,而是行尾的回车(CR)和换行(LN)。
作者: lhjoanna 时间: 2008-11-29 23:14
原来如此啊,以前总以为回车与换行是一个的。搜索了一下资料,发现回车是回到行首,换行是换到下一行。用二进制编辑器看行尾#13#10,十六进制看行尾为0d0a。说明我们平常输入的回车符其实是两个字符。#13为回车,#10为换行。0d为回车,0a为换行。大家把0d或0a改为00看看。又学到了一点!
[ 本帖最后由 lhjoanna 于 2008-11-29 23:20 编辑 ]
作者: myzwd 时间: 2009-3-2 17:52 标题: 回复 1楼 的帖子
@echo off
set /p tt=please input---
set n=-1
call:circle
goto:eof
:circle
setlocal
set tt1=%tt:~,1%
set tt2=%tt:~1%
set tt=%tt2%_%tt1%
set /a n+=1
if "%tt1%" neq "_" goto circle
echo %n%
endlocal
作者: pzspdl 时间: 2009-3-4 22:40
我还是看看别人的吧,我太菜了
作者: keen 时间: 2009-3-26 23:45 标题: 回复 4楼 的帖子
法四中
for /f "tokens=1 delims=:" %%i in ('findstr /o .* a.txt') do set /a length=%%i-2&if not %%i equ 0 echo 共有%length%个字符&goto end
应该是一行,估计网页原因,显示为两行,所以我觉得是不是%length% 改为!length!
如不对,请指正!
作者: taofan712 时间: 2017-1-17 16:56
- @echo off
- set str=123ABC上中下
- set /a n=0
- :loop
- set str=%str:~0,-1%
- if "%str%" neq "" (set /a n+=1 & goto loop)
- echo 这个字符串是%n%位数 & pause>nul
复制代码
作者: Nsqs 时间: 2017-1-17 20:16
回复 12# batman - @echo off
- set n=12345689
- set n=%n%;
- for /f "tokens=1 delims=:" %%1 in ('^(echo %n:;=^&echo.%^)^|findstr /o ".*"')do set /a c=%%1-3
- echo %c%
- pause
复制代码
不用临时文件
作者: taofan712 时间: 2017-2-15 10:59
- @echo off
- set str=123ABC上中下
- :loop
- set /a a+=1
- set str=%str:~0,-1%
- if "%str%"=="" (echo %a%&pause>nul ) else goto loop
复制代码
作者: taofan712 时间: 2017-3-9 22:17
本帖最后由 taofan712 于 2017-3-10 16:26 编辑
- @echo off
- set "var=qwertyuioplkjhgfdsazxcvbnm"
- call :strLen var long
- echo;%long%
- pause&exit /b
- :strLen
-
- ( SETLOCAL ENABLEDELAYEDEXPANSION
- set "str=A!%~1!"
- set "len=0"
- for /L %%A in (12,-1,0) do (
- set /a "len|=1<<%%A"
- for %%B in (!len!) do if "!str:~%%B,1!"=="" set /a "len&=~1<<%%A"
- )
- )
- ( ENDLOCAL
- IF "%~2" NEQ "" SET /a %~2=%len%
- )
- goto :eof
复制代码
很偏门,但很好用,不忍独享,文件出处http://www.it1352.com/328587.html
作者: 回家路上 时间: 2017-3-10 13:51
回复 21# taofan712
最好标明出处,方便看到的朋友系统学习。如果是你没记出处,就是你的问题了。
http://www.bathome.net/thread-11799-1-1.html
结合帖子中设置为一个变量调用的思路,也试着把这种方式写成一行试试- @echo off & setlocal enabledelayedexpansion
- set "_strlen=set $=#^!$^!&set ##=&for /l %%a in (12,-1,0)do set/a"##^|^=1^<^<%%a"&for %%b in (^!##^!)do if ^!$:~%%b^!.==. set /a"##^&^=~1^<^<%%a""
-
- for %%i in (
- 12345678901234567890123456789012345678901234567890
- 1234567890123456789012345678901234567890
- 123456789012345678901234567890
- 12345678901234567890
- 1234567890
- 1
- ) do (
- set "$=%%i" & (%_strlen%)
- echo;!##! : %%i
- )
-
- pause & exit /b
复制代码
作者: diverpan 时间: 2017-3-15 21:40
参变量的最少个数为1,最少循环次数也为1,思路清晰了,也挺好写的
作者: 老刘1号 时间: 2017-5-14 14:44
本帖最后由 老刘1号 于 2017-5-14 14:57 编辑
8086ASM(DEBUG版)- Echo off&CLS
- IF /i "%PROCESSOR_ARCHITECTURE%" EQU "AMD64" (
- echo DEBUG和8086_ASM不支持64位的系统。
- Pause&Exit
- )
- >"%Tmp%\DEBUGASM.TMP" (
- Echo A
- Echo MOV BX,20 ;一段安全的空间
- Echo MOV SS,BX
- Echo MOV SP,80 ;清理安全空间
- Echo MOV CX,40 ;循环次数(HEX)=清理字节数(128B)/入栈大小(2B)
- Echo SUB BX,BX ;清空BX
- Echo PUSH BX ;执行入栈(清理)
- Echo LOOP 10D ;循环压栈
- Echo SUB CX,CX ;清空CX
- Echo INT 21H
- Echo.&Echo G)
- Set /P str=Input a string:
- Echo E20:0 "%STR%">>"%Tmp%\DEBUGASM.TMP"
- More +25 "%~0" >>"%Tmp%\DEBUGASM.TMP"
- For /f "Tokens=2" %%a in (
- '^<%tmp%\DEBUGASM.TMP DEBUG^|Findstr /c:"0020:0000"'
- ) Do Set /a Strlen=0x%%a
- DEL %tmp%\DEBUGASM.TMP
- Echo %Strlen%&Pause&Exit /b
- A100
- MOV BX,20 ;一段安全的空间
- MOV DS,BX
- SUB BX,BX ;清空BX
- MOV CL,[BX] ;获取Ascii
- JCXZ 10E ;判断是否为NUL并跳出
- INC BX ;计数
- JMP 107 ;循环读取
- MOV [0],BX ;将字符串长度写入内存
- INT 21H
-
- G
- D20:0 0
- Q
- Q
复制代码
作者: happy886rr 时间: 2017-5-14 17:39
回复 24# 老刘1号
超过65个字符就不行。
作者: 老刘1号 时间: 2017-5-20 18:50
回复 25# happy886rr
峰值为71个
DEBUG一行就那么长...
作者: happy886rr 时间: 2017-5-20 22:05
回复 26# 老刘1号
很棒,71个够用了,一般太长的都直接C语言解决。
作者: 老刘1号 时间: 2017-5-21 13:23
回复 27# happy886rr
感谢鼓励,
新版本出炉,峰值达到255个
用法: Batname <String>
继续学习汇编~~- @Echo off
- IF /i "%PROCESSOR_ARCHITECTURE%" EQU "AMD64" (
- echo DEBUG和8086_ASM不支持64位的系统。
- Pause&Exit
- )
- Set "Str=%*"
- >%tmp%\DEBUGASM.TMP (
- ECHO A20:0
- ECHO DB "%Str:~,70%"
- ECHO DB "%Str:~70,70%"
- ECHO DB "%Str:~140,70%"
- ECHO DB "%Str:~210,45%"
- ECHO DB 0
- ECHO.
- MORE +20 "%~0"
- )
- For /f "Tokens=2" %%a in (
- '^<%tmp%\DEBUGASM.TMP DEBUG^|Findstr /c:"0020:0000"'
- ) Do Set /a Strlen=0x%%a 2>nul
- Echo %Strlen%&DEL /F %tmp%\DEBUGASM.TMP&Exit /b
- A100
- MOV BX,20 ;一段安全的空间
- MOV DS,BX
- SUB BX,BX ;清空BX
- MOV CL,[BX] ;获取Ascii
- JCXZ 10E ;判断是否为NUL并跳出
- INC BX ;计数
- JMP 107 ;循环读取
- MOV [0],BX ;将字符串长度写入内存
- INT 21H
-
- G
- D20:0 0
- Q
- 老刘制作~
复制代码
作者: happy886rr 时间: 2017-5-21 14:56
回复 28# 老刘1号
255个已经够用了。再长的批处理自己也能计算。
作者: 懒虫阿布 时间: 2018-7-23 21:14
- @echo off
- setlocal enabledelayedexpansion
-
- ::%1 字符串
- set str=%1
-
- set strLen=0
- :StartLoop
- if "%str%"=="" goto EndLoop
- set str=!str:~1!
- set /a strLen+=1
- goto StartLoop
- :EndLoop
-
- echo %1 length is !strLen!
复制代码
作者: 唯尘 时间: 2024-1-14 21:28
@echo off
set /p input=请输入需要检测的字符串:
set var=%input%
:sc_start
set var=%var:~0,-1%
set /a n+=1
if not "%var%"=="" (goto sc_start)
echo 字符串长度是%n%
pause>nul&exit
作者: 唯尘 时间: 2024-8-13 08:35
@echo off&setlocal enabledelayedexpansion
set /p var=请输入需要判断的字符串:
:agin
set var=!var:~0,-1!
set /a n+=1
if not "!var!"=="" goto :agin
echo 字符串长度:!n!
pause>nul
欢迎光临 批处理之家 (http://www.bathome.net/) |
Powered by Discuz! 7.2 |