批处理之家's Archiver

batman 发表于 2008-8-1 22:37

【练习-007】批处理去除指定字符前所有的0

[color=blue]
如文本1.txt:[code]0000acb0h
0b0c00a000s
0000h00ga00
a0000000[/code]通过批处理将文本所有字符串字符a前的0去除输出如下:[code]acb0h
bca000s
hga00
a0000000[/code]要求:代码简洁、高效、通用,不生成临时文件
-----------------------------------------------------
本题已有较完美的解答方案:
  见9楼pusefalse版主和本人10楼的方案。[/color]

[[i] 本帖最后由 batman 于 2008-8-4 17:55 编辑 [/i]]

pusofalse 发表于 2008-8-2 00:12

********************
屏蔽,看错题意了。

[[i] 本帖最后由 pusofalse 于 2008-8-2 04:20 编辑 [/i]]

null 发表于 2008-8-2 01:15

我失败了,但我有个问题
我的测试代码如下:
[code]@echo off
for /f "tokens=1,2 delims=a" %%i in (1.txt) do (
set a=%%i
set a=%a:0=%
echo %a%a%%j
)[/code]

结果为:
[code]
acb0h
a000s
a00
a
[/code]

在CMD中运行
set a=0b0c00a000s
set a=%a:0=%
echo %a%
的结果正常,显示为:bcas
为什么在上面的测试代码中结果却全部变没了呢?

pusofalse 发表于 2008-8-2 04:05

[quote]原帖由 [i]null[/i] 于 2008-8-2 01:15 发表 [url=http://bbs.bathome.net/redirect.php?goto=findpost&pid=6304&ptid=1310][img]http://bbs.bathome.net/images/common/back.gif[/img][/url]
我失败了,但我有个问题
我的测试代码如下:
@echo off
for /f "tokens=1,2 delims=a" %%i in (1.txt) do (
set a=%%i
set a=%a:0=%
echo %a%a%%j
)

结果为:

acb0h
a000s
a00
a


在CMD中运行
... [/quote]
你的这两个代码输出的结果是理所当然的。第一个因为没有开启变量延迟,即使开启了,输出的结果也不会正确。
第二个。你测试如下代码。[code]
set a=0b0c00a000s&echo %a%
pause[/code]保存为bat。运行,你会发现a的值并不是你所想的那样,而是显示echo处于关闭状态。
这是因为CMD命令解释器在读到set a=0b0c00a000s&echo %a%这一条完整的语句时,发现a用%%闭合,是个变量,会把它替换成之前所赋给它的字符串常量,并把它打印出来。而在这条完整的语句之前并没有给a赋值,即是空值。所以才会显示echo处于关闭状态。请理解“一条完整的语句”的意思。
set a=0b0c00a00s&echo %a% 这才是一条完整的语句。
同样的,for语句中给a赋值,然后又在for中引用%a%,在这之前,CMD早就把它替换为空值了,所以你的代码会出错。
如何避免这种出错呢,要用到变量延迟了。
setlocal enabledelayedexpansion 这条语句的意思即是开启变量延迟。它的作用就是要告诉CMD,在读到一条完整的语句时,不要急匆匆地扩展变量。而是在执行复合语句(for语句或if语句中其后用一对圆括号闭合的所有语句称为复合语句,用&或&&连接的也是复合语句。)中的某单条语句之后,再执行变量的扩展,也就是说,这个变量扩展的行为被延后了。在开启延迟之后,在for中给变量a赋值,又在for中引用a,此时,就不应用%%将其闭合了,而是用!!。
你的代码应该是这样。[code]
@echo off&setlocal enabledelayedexpansion
for /f "tokens=1,2 delims=a" %%i in (1.txt) do (
set a=%%i
set a=!a:0=!
echo !a!a%%j
)
pause[/code]但输出的结果仍不符合楼主的要求,这就要看你的了。

还要记得,如果在复合语句之外再次引用变量,此时它的值是在复合语句之内最后得到的值。
如下代码:[code]
@echo off&setlocal enabledelayedexpansion
for /l %%a in (100 1 199) do set var=%%a&echo !var:~1!
echo %var%
pause[/code]关于变量延迟,搜索一下,多做测试很快就能明白了,我说的很粗糙。

[[i] 本帖最后由 pusofalse 于 2008-8-2 04:06 编辑 [/i]]

null 发表于 2008-8-2 11:07

回复 4楼 的帖子

我明白了,十分感谢!

batman 发表于 2008-8-2 12:00

提示一下:
  开启变量延迟是我们常用的方法,但大家想一想本题是不是可以不开变量延迟?

batman 发表于 2008-8-3 13:36

我们出题目的目的在于让大家都活跃下思路,在设法解题的过程中能得到提高。

本题确实不难,希望大家充分利用好每次出题的机会来提高自己,同时也可获
得一定的积分奖励(当然这并不是目的所在)。

ieutk 发表于 2008-8-3 14:32

[code]@echo off&setlocal enabledelayedexpansion
for /f "usebackq skip=12 delims=" %%a in ("%~dpnx0") do (
        set "var=%%a"
        set "var=!var:a=a#!"
        for /f "tokens=1* delims=#" %%i in ("!var!") do (
                 set "eo1=%%i"&set "eo2=%%j"
                 set "eo1=!eo1:0=!"
                 set "eo2=!eo2:#=!"
                 echo.!eo1!!eo2!
            )
    )
pause&goto :eof
0000acb0ha0
0b0c00a000s
0000h00ga00
a0000000a
a00d0sa000d0a0[/code]

[[i] 本帖最后由 ieutk 于 2008-8-3 15:09 编辑 [/i]]

pusofalse 发表于 2008-8-3 18:40

[code]@echo off
for /f "delims=" %%. in (1.txt) do (
   set "str=%%."
   call,set "str=%%str:*a=%%"
   for /f "delims=a" %%{ in ("%%.") do (
         set "var=%%{"
        call,echo.%%var:0=%%a%%str%%
  ))
pause>nul[/code]

来个怪异的。^_^

batman 发表于 2008-8-4 17:52

我的解:[code]@echo off
for /f "tokens=1,2 delims=a" %%i in (1.txt) do (
     if "%%j" neq "" (
        set "str=%%i"
        call,set "str=%%str:0=%%"
        call,echo %%str%%a%%j
        ) else (
        echo a%%i
     )
)
pause>nul[/code]

more 发表于 2008-8-5 11:55

如果测试文本如下,要求去除第一个a前的0,那么只有9楼的代码成功:[code]0000acb0a0h
0ab0c00a000s
0000h00ga00
00a000a0000[/code]

[[i] 本帖最后由 more 于 2008-8-5 11:59 编辑 [/i]]

batman 发表于 2008-8-5 12:56

批处理之所以如此得到大家的青睐,是因为它可以现写现用很方便,
同时从一另一层面上就要求我们具体问题具体对待,相信谁也不会
回为要解决一个普通的问题而写出一个适合出所有此类问题的代码
吧,如真要这样做,在时间上的损耗将是一笔无可估量的损失,我
们也会因此而得不偿失。

ieutk 发表于 2008-8-5 13:36

[quote]如果测试文本如下,要求去除第一个a前的0,那么只有9楼的代码成功[/quote]

用11楼提供的字符经测试,8,9楼代码都通过,10楼没有通过


[quote]批处理之所以如此得到大家的青睐,是因为它可以现写现用很方便,
同时从一另一层面上就要求我们具体问题具体对待,相信谁也不会
回为要解决一个普通的问题而写出一个适合出所有此类问题的代码
吧,如真要这样做,在时间上的损耗将是一笔无可估量的损失,我
们也会因此而得不偿失。[/quote]

呵呵,说的也是,有时在写代码的时候会出现考滤问题不全而导致代码不通用。

Clark2505 发表于 2008-8-5 21:20

可怜的我为什么都学不会for的用法??
各位大大怎么学的??

shqf 发表于 2008-8-5 21:52

[code]
@echo off&setlocal enabledelayedexpansion
for /f "tokens=1,2 delims=a" %%i in (1.txt) do (
set aftera=%%j
if "!aftera!"=="" set aftera=%%i
set a=%%i
set a=!a:0=!
echo !a!a!aftera!
)
pause
[/code]

[[i] 本帖最后由 shqf 于 2008-8-5 21:57 编辑 [/i]]

null 发表于 2008-8-6 12:30

[quote]原帖由 [i]pusofalse[/i] 于 2008-8-3 18:40 发表 [url=http://bbs.bathome.net/redirect.php?goto=findpost&pid=6422&ptid=1310][img]http://bbs.bathome.net/images/common/back.gif[/img][/url]
@echo off
for /f "delims=" %%. in (1.txt) do (
   set "str=%%."
   call,set "str=%%str:*a=%%"
   for /f "delims=a" %%{ in ("%%.") do (
         set "var=%%{"
        call,echo.%%var:0=%%a%%str%% ... [/quote]

请高手帮忙解释一下可以吗,我对里面的一些语法不太了解
像上面的"delims="这样的分隔符是代表什么意思,还有这个%%.这又是什么意思,同样,还有下面的%%{

ieutk 发表于 2008-8-6 15:12

"delims="    取消以空格作为分隔符
%%.
%%{
之类的你可以看作%%i   %%a

null 发表于 2008-8-6 17:30

[quote]原帖由 [i]ieutk[/i] 于 2008-8-6 15:12 发表 [url=http://bbs.bathome.net/redirect.php?goto=findpost&pid=6710&ptid=1310][img]http://bbs.bathome.net/images/common/back.gif[/img][/url]
"delims="    取消以空格作为分隔符
%%.
%%{
之类的你可以看作%%i   %%a [/quote]

"delims="    取消以空格作为分隔符[color=red][不太明白][/color]
那这种形式一般是用在什么样的场合呢,具体的作用又是什么,可以结合例子说明一下吗?

感谢!

huahua0919 发表于 2008-8-6 18:03

[code]@echo off
for /f "delims=" %%i in (a.txt) do (
set a=%%i
setlocal enabledelayedexpansion
for /l %%i in (1 1 10) do (
set a=!a:0a=a!
)
echo !a!
endlocal
)
pause[/code]

pusofalse 发表于 2008-8-6 19:55

楼上的朋友,测试果真正确吗。

pusofalse 发表于 2008-8-6 20:14

只看delim这个单词是分隔的意思。
它用在for的选项中当然就是指定分隔符的意思,看其后的s,可以指定不止一个。
举个例子就简单了。从文件中取值。
a.txt[code] bbs bat home [/code]你知道从a.txt中提取出bat 是用for /f "tokens=2 [color=red]delims=[/color] " %%a in (a.txt) do @echo %%a
红色那处(包括=之后的空格)可有可无,因为for 默认就是以空格或跳格或等号作为分隔符的。
以XP中文版为例,提取出当前时间,并输出如下形式yyyymmdd
for /f "tokens=1-3 delims=- " %%a in ('date/t') do @echo %%a%%b%%c
"tokens=1-3 delims=- " 取命令结果中的1-3列,看下命令结果只有两列,如何做呢,就要用delims制定分隔符了,分隔符多指定一个- 看下,不就变成4列了吗。delims=-之后有空格,否则,第三列会是这样[color=blue]06 星期三[/color][color=dimgray],而不会再以空格作为分隔符,06为当前日期。[/color]
[color=#696969]加深。[/color]
[color=#696969]a.txt[/color]
[color=#696969][code]abcdefghijkl[/code][/color]
[color=#696969]只提取出hijkl[/color]
[color=#696969][code]
for /f "tokens=2 delims=g" %%a in (a.txt) do @echo %%a[/code][/color]
[color=#696969][/color]
[color=#696969]%%{ %%.这样的非常少见,所以说怪异。[/color]
[color=#696969]for /f "tokens=1-31" %%a in (a.txt) do echo %%a...%%z...[/color]
[color=#696969]超过z之后要用{表示。[/color]
[color=#696969]for中的变量顺序完全是由ASSCII码的大小来排列的。[/color]
for /f "tokens=1-3" %%" in (a.txt) do @echo %%"...
其后要用什么表示呢。
看下,"的十进制asscii为34,只需知道哪个是35,36 就可以输出第2-3列了。
十进制asscii对应35,36的分别是# $
但"是特殊字符,其前要加^转义。所以这个例子中,若全部输出1-3列,正确的应该是[code]
for /f "tokens=1-3" %%^" in (a.txt) do @echo %%^" %%# %%$[/code]

[[i] 本帖最后由 pusofalse 于 2008-8-6 20:25 编辑 [/i]]

null 发表于 2008-8-7 17:32

明白了,我上面只是对"delime="不太理解,版主是个好心的同志哇,讲得这么细,感谢

昨天自己写了个测试代码运行了一下已经完全明白了。

for /f %%i in ('dir') do @echo %%i  
测试运行结果:
驱动器
卷的序列号是
C:\Documents
2008-08-05
2008-08-05
2008-04-24
2008-08-03
2008-04-24
2008-08-02
0
6

for /f "delims=" %%i in ('dir') do @echo %%i
运行结果:
驱动器 C 中的卷是 WINXP
卷的序列号是 9CAA-3031
C:\Documents and Settings\Administrator 的目录
2008-08-05  11:20    <DIR>          .
2008-08-05  11:20    <DIR>          ..
2008-04-24  18:01    <DIR>          Favorites
2008-08-03  00:50    <DIR>          Phone Browser
2008-04-24  15:29    <DIR>          「开始」菜单
2008-08-02  23:23    <DIR>          桌面
               0 个文件              0 字节
               6 个目录  6,371,704,832 可用字节

我从两个结果的对比中得到的理解即为:
不加"delims="这个参数的话,for 就会默认以空格作为分隔符(这样就只会显示左边的一列所返回的结果),加上这个参数可以取消以空格作为分隔符。

null 发表于 2008-8-7 17:37

%%{ %%.这样的非常少见,所以说怪异。
for /f "tokens=1-31" %%a in (a.txt) do echo %%a...%%z...
超过z之后要用{表示。
for中的变量顺序完全是由ASSCII码的大小来排列的。
for /f "tokens=1-3" %%" in (a.txt) do @echo %%"...
其后要用什么表示呢。
看下,"的十进制asscii为34,只需知道哪个是35,36 就可以输出第2-3列了。
十进制asscii对应35,36的分别是# $
但"是特殊字符,其前要加^转义。所以这个例子中,若全部输出1-3列,正确的应该是
复制内容到剪贴板代码:

for /f "tokens=1-3" %%^" in (a.txt) do @echo %%^" %%# %%$


对于版主同去对于这部分的解释,我也明白了,十分感谢。。。

不过我也产生了一个疑问,
@echo off
for /f "delims=" %%. in (1.txt) do (
   set "str=%%."
   call,set "str=%%str:*a=%%"
   for /f "delims=a" %%{ in ("%%.") do (
         set "var=%%{"
        call,echo.%%var:0=%%a%%str%% ...
按照我的理解来说,这里的%%{  %%.跟%%a %%b并没有什么实质上的不同啊,那为什么要用在这里呢??

浅默 发表于 2008-8-7 20:32

a00000008
9楼的代码在处理上面的情况时不理想

pusofalse 发表于 2008-8-7 21:35

回复 24楼 的帖子

多谢兄弟指出。我明天再来看下哪里出错了,今天太累了,不好意思。

terse 发表于 2008-8-7 23:52

前面几个测试后 或多或少的有些问题  写一个
[code]@echo off&setlocal enabledelayedexpansion
for /f "delims=" %%i in ('more/e +9 %0') do (
   set "str=%%i"
   call set "var=%%str:*a=!str!a%%"
   call set "var=%%var:!str!=%%"
   if not "!var!"=="" (
   call set "var1=%%str:!var!=%%"
   set "var1=!var1:0=!"&echo !var1!!var!) else echo %%i)
pause>nul&exit
560000h57
0000acb0ha22a
0b0c00a00a0s
0000h00ga0a0
a00000000a
0000h00g200
00000000a0a
a00000000
00000000a
aaaaa[/code]

youxi01 发表于 2008-8-8 00:39

去if,增强代码的健壮,测试代码:[code]@echo off
for /f "delims=" %%c in (1.txt) do (
        for /f "delims=a tokens=1,*" %%i in ("0%%c") do (
                set var=%%i
                call echo.%%var:0=%%a%%j
))
pause>nul[/code]

youxi01 发表于 2008-8-8 00:46

不过话说回来,题目有很多细节没说清楚
如,a的个数?a的大致位置?等等问题

其实,所谓的通用代码一般都是比较累赘的,所以写的代码一般都具有很强的针对性

terse 发表于 2008-8-8 13:02

[quote]原帖由 [i]youxi01[/i] 于 2008-8-8 00:39 发表 [url=http://bbs.bathome.net/redirect.php?goto=findpost&pid=6810&ptid=1310][img]http://bbs.bathome.net/images/common/back.gif[/img][/url]
去if,增强代码的健壮,测试代码:@echo off
for /f "delims=" %%c in (1.txt) do (
        for /f "delims=a tokens=1,*" %%i in ("0%%c") do (
                set var=%%i
                call echo.%%var:0=%%a%%j
))
pause>nul [/quote]
原文本没有a的行会去掉不应去掉的0
在原文本全a的行只显一个a

huahua0919 发表于 2008-8-8 13:38

我不明白为什么我的代码不正确,
只是针对你题目而已。
其实想要做到通用只要计算最长字符的长度即可。

页: [1] 2

Powered by Discuz! Archiver 7.2  © 2001-2009 Comsenz Inc.