批处理不像其他的语言有专门的命令或函数来获取字符串的长度,要想判断字符串的长度,一切都要自力更生,通过自己编写代码予以解决。你可别小看这个简单的任务,真正要编写一段判断字符串长度的代码,其中还有不少值得注意的地方呢。
以下是本人在前人工作的基础上编写的一段较为完美的演示代码,大家先拿来玩玩,玩过之后再看后面的分析。- @echo off
-
- :Main
- cls
- set num=0
- set str=
- set /p str=请输入一串测试字符:
- if not defined str goto end
- set "str=%str:"=%"
- if defined str call :count
-
- :end
- echo 字符串去掉所有的双引号后,长度为:%num%
- pause
- goto Main
-
- :count
- set /a num+=1
- set "str=%str:~1%"
- if defined str goto count
- goto :eof
复制代码 以上这段代码的基本思路是:先去掉字符串中所有可能存在的双引号,然后,抛弃字符串首位的字符之后,再判断剩下的字符串是否为空;在抛弃首位字符的同时,计数器加1;若处理后的字符串不为空,则进入循环体:count,再重复执行抛弃首位字符、计数器加1、判断剩下的字符串是否为空这一过程,直到剩下的字符串是空值为止。
思路是简单的,代码是短小的,但是,陷阱也是随处可遇的,一不留神,就会栽了跟斗。
因为这段代码是可以重复演示的,所以,最开始需要对变量进行初始化:计数变量num赋初值为0,字符串变量str进行清空处理,否则,进行第二次演示的时候,上一次的结果将会带到第二次计算中来,导致最终结果出错。
在这段代码中,if defiend str 这样的语句出现的频率很高,达到了3次:第1次是判断是否输入了字符串,第2次是在替换掉所有可能存在的双引号后,判断变量的值是否为空,第3次是在抛弃首位字符后,判断剩下的字符串中是否为空。
(补充知识:if defiend str 语句是判断str的值是否为空的终极方法,使用 if "%str%"=="" 的句式是不完美的,具体分析请看这篇文章:判断变量值是否为空的终极方法 http://bbs.bathome.net/thread-4046-1-1.html)
也许有人说,if defined str 没必要保留那么多,只需要保留最后一个就可以了。
果真如此吗?
我们来分析一下是否有必要保留3个if defined str。
当我们取消第1条 if defined str 语句后,如果输入的是空值,set "str=%str:"=%" 执行之后,str的值将为"=,而不是空值(为什么需要使用set "str=%str:"=%",请看后续分析),结果将出错,因此,第1条 if defined str 必须保留;
如果我们取消第二条 if defined str ,直接使用call :count,那么,当 set "str=%str:"=%" 执行的结果令str的值为空的时候,第一次执行到:count标签段下的 set "str=%str:~1%" 时,因为str的初始值为空,则执行字符截取之后,str的结果将为~1,很显然,最终的结果将是错误的,因此,第2条 if defined str 语句也需要保留。
最后一条 if defined str,是判断何时跳出循环体的语句,必须保留。
对于最后的提示信息:字符串去掉所有的双引号后,长度为:%num%,很多人可能会大惑不解:为什么要去掉所有的双引号呢?难道不能统计双引号吗?
对于双引号,确实是个令人头痛的问题,这得从批处理兼容特殊字符谈起。
在批处理中,因为>、<、|、&等符号有特殊用法,若带入批处理作为一般字符处理,需要使用特殊的方法消除它们的原始用法,比如 set "str=%str:~1%" 这句,就是在 str=%str~1% 的首尾用引号把字符串括起来,消除那些特殊字符的特殊用法,当然,你也可以把 set "str=%str:~1%" 写为 set str="%str:~1%",同样能处理那些特殊字符,只不过,后面这一种会把双引号对本身作为 str 的值,在后续操作中还要对多出来的引号对做额外处理,而前一种写法则不会这样。但是,在这里又存在一个两难的选择:当其他特殊符号被正确处理之后,在特定情况下,双引号本身却不能被正确处理,比如偶数个引号后紧跟<、>、|等字符,这是由于引号对配对不正确引起的,因此,要么放弃对其他特殊字符的兼容而保留对引号的处理,要么先去掉所有的双引号而兼容更多的其他特殊字符。在本例中,采取的方案是后者,因此,在输入字符串之后,先用 set "str=%str:"=%" 去掉字符串中所有可能存在的双引号。
set "str=%str:"=%" 一句,猛一看上去,两个str、三个双引号,完全没法分析语句结构,其含义是比较难以理解的。实际上,这是一条字符串替换语句,原型为:set str=%str1:str2=str3%,含义为:把 str1 中的字符串str2替换为str3,并把替换后的结果赋予str,一旦你把原型语句中的 str2 换为双引号,把 str3 换为空值,再在 set 语句的首尾加上兼容特殊字符的双引号之后,你就会明白 set "str=%str:"=%" 的含义为:把 str 这个变量中所有可能存在的双引号去掉,把结果再重新赋予str。具体分析过程可以参考这个帖子:[转帖]如何从用户传入的参数中去掉引号? http://bbs.bathome.net/viewthread.php?tid=2397
在本例中,set "str=%str:"=%"和set "str=%str:~1%"互为呼应,缺一不可。
最后,我们来看一个小技巧: set /a num+=1。这是一条累加语句的缩写,原型为 set /a num=num+1,累加额度为每次在原有基础上加1,当然,你也可以加大累加额度,比如写成 set /a num+=2、set /a num+=3之类。与此类似的写法有:set /a num*=2表示累乘,set /a num/=2表示累除。缩写形式能减少代码量,也能增强可读性,是大家常用的书写格式。
总结一下经验教训:
1、随时初始化变量是个好习惯;
2、随时检测变量的值是否为空,能消除不少隐患;
3、兼容特殊字符,请使用引号对把字符串括起来,但是请首先保证要处理的字符串中没有双引号;
______________________________________________________
后记:
本文发表之后,zqz0012005提供了一个更加完美的代码,经过初步测试,能兼容除空字符串、百分号外的其他所有特殊情形,具有更高的兼容性,也更简洁,现发在此处,等我空闲时间多了之后,再做一个对比分析,有意分析这段代码的,也不妨另开新帖加以讨论:- @echo off
- set "str=Hello, bat! <^_^>%%""
- call :strlen len
- echo %len%
- pause&goto :eof
-
- :strlen
- setlocal EnableDelayedExpansion&set n=0
- :strlen_loop
- if "!str:~%n%,1!" neq "" set /a n+=1&goto strlen_loop
- endlocal&set "%~1=%n%"&goto :eof
复制代码
|