批处理之家's Archiver

batman 发表于 2008-7-27 10:23

【练习-004】批处理重命名特殊文件名

[color=blue]---------------------------------------------------------------------------------------------------------------------------------------------

文件夹下有三个由字母、数字、汉字、特殊字符组成文件名的文件同时批处理自身也在其中:
一b!a!1235@_ s%#8i  三 c.rar
h^e12 0~%l%!p!@. s321-的文件.txt
%o%%% !O!ffi9~  ce$- Wor8d29 文档.docx
重命名.bat
图1:
[attach]1240[/attach]
---------------------------------------------------------------------------------------------------------------------------------------------
要求运行批处理将这三个文件文件名中的数字、汉字、特殊字符全部(含空格)去掉,而重命名为只含字母的文件,但
后缀名不能更改,同时批处理自身名字不能更改,重命名后:
basic.rar
helps.txt
oOfficeWor.docx
重命名.bat
图2:

[attach]1241[/attach]
---------------------------------------------------------------------------------------------------------------------------------------------
要求:代码简洁、通用、效率不至于太低。
---------------------------------------------------------------------------------------------------------------------------------------------
[/color]

pusofalse 发表于 2008-7-27 16:59

[code]
@echo off
for %%a in (*.*) do (
    if "%%~nxa" neq "%~nx0" (
        set "name=%%~na"
        setlocal enabledelayedexpansion
        set name1=!name!
        call :lp
        ren "!name!%%~xa" "!nam!%%~xa"
        set "nam="
        endlocal
)
)
pause
:lp
if defined name1 (
set "var=!name1:~,1!"
if "!var!" leq "Z" (
if "!var!" geq "a" (
set "nam=!nam!!var!"
))
set "name1=!name1:~1!"
goto lp
)[/code]我是最怕特殊字符的。。。T.T

[[i] 本帖最后由 pusofalse 于 2008-7-27 18:48 编辑 [/i]]

batman 发表于 2008-7-27 20:12

if "!var!" leq "Z" (
if "!var!" geq "a" (
这两句用得好,不过我还没找相关理论来支持这样的用法,这又回到了if究竟是怎么进行字
符判断的这个问题上来了。

要指出的是在这里if应该为if /i。

pusofalse 发表于 2008-7-27 21:08

我觉得不用改啊
我这里的z是大写啊~

[[i] 本帖最后由 pusofalse 于 2008-7-27 21:09 编辑 [/i]]

batman 发表于 2008-7-27 21:47

来个新思路(思路是namejm的);[code]
@echo off
set "code=a b c d e f g h i j k l m n o p q r s t u v w x y z"
for /f "delims=" %%a in ('dir /s /a-d /b') do (
    if "%%~nxa" neq "重命名.bat" (
       set "str=%%~na"&set "file=%%a"&set "var=%%~na"
       setlocal enabledelayedexpansion
       for %%i in (%code%) do set "str=!str:%%i=!"
       set "str=!str: =!"&call :lp
       ren "!file!" !files!%%~xa
       endlocal
))
goto :eof
:lp
set /a n+=1
for /f "tokens=%n% delims=%str% " %%a in ("%var%") do (
     if "%%a" neq "" set "files=!files!%%a"&goto lp
)[/code][color=blue]
描述下整体思路吧:[/color]
[color=#0000ff]----------------------------------------------------------------------------------------------------------------------------------------------------[/color]
[color=blue]
     大家看到了题中的文件名是由字母+数字+特殊字符+汉字组成的,看起来很复杂,但我们是不是可以换个角度这样看:文件名是由分隔符+字母组成的(将数字、特殊字符、汉字全看成分隔符),是不是简单多了,呵呵,麻烦的还在后面。。。[/color]
[color=#0000ff]----------------------------------------------------------------------------------------------------------------------------------------------------[/color]
[color=blue]     那么,我们又遇到问题了:数字、特殊字符还好说数量是有限的,汉字可是个麻烦事啊,我们总不能在delims=后面把所有汉字全写上吧(况且这个长度是有限的)?这是不可能的,怎么办呢?于是,我们可以先将文件名中不是字母的字符全提出来,怎么提?这就要用到变量替换了,将26个字母全替换为空。[/color]
[color=#0000ff]----------------------------------------------------------------------------------------------------------------------------------------------------[/color]

[color=blue]    有人会说了效率有问题,这里确实存在效率问题,但大家想一下比较逐字符的判断的效率这个还是要高一点,为什么?假设一个文件名有十几个a,用逐字符就要判断十几次,而变量替换只一次就搞定了。[/color]
[color=#0000ff]----------------------------------------------------------------------------------------------------------------------------------------------------[/color]

[color=blue]    经过这样替换后的字符串中是不是只留下了不是字母的字符。现在只要把其来做为分隔符(别忘了加上空格)来提取文件名中的所有的字母了,而剩下的工作就只是技术处理了。[/color]
[color=blue]----------------------------------------------------------------------------------------------------------------------------------------------------





[/color]

[[i] 本帖最后由 batman 于 2008-7-28 01:23 编辑 [/i]]

more 发表于 2008-7-28 00:46

[code]@echo off
for /f "delims=" %%a in ('dir /b/a-d "*.*"') do (
   if not "%%~nxa"=="%~nx0" (
      set "more=%%a"&set "mo=%%~na"&set "n=0"&set "ming="
      setlocal enabledelayedexpansion
      call :mo
      ren "!more!" "!ming!%%~xa"
      endlocal
   )
)
pause&exit
:mo
if not "!mo:~%n%,1!"=="" (
   set "niu=!mo:~%n%,1!"
   call :niu
   set /a "n+=1"
   goto :mo
)
goto :eof
:niu
for %%b in (a b c d e f g h i j k l m n o p q r s t u v w x y z) do (
   if /i "%niu%"=="%%b" (set "ming=!ming!%niu%"&goto :eof)
)[/code]

more 发表于 2008-7-28 00:53

5楼的代码运行不成功

batman 发表于 2008-7-28 01:16

[quote]原帖由 [i]more[/i] 于 2008-7-28 00:53 发表 [url=http://bbs.bathome.net/redirect.php?goto=findpost&pid=6008&ptid=1251][img]http://bbs.bathome.net/images/common/back.gif[/img][/url]
5楼的代码运行不成功 [/quote]
我都测试了N次了,怎么会不成功

more 发表于 2008-7-28 10:37

[quote]原帖由 [i]batman[/i] 于 2008-7-28 01:16 发表 [url=http://bbs.bathome.net/redirect.php?goto=findpost&pid=6009&ptid=1251][img]http://bbs.bathome.net/images/common/back.gif[/img][/url]

我都测试了N次了,怎么会不成功 [/quote]
昨天晚上测试的时候不行,今天早上却可以,怪...

terse 发表于 2008-8-5 01:49

[code]@echo off
for %%i in (a b c d e f g h i j k l m n o p q r s t u v w x y z) do set %%i=a
for %%i in (*.*) do (
    if not "%%~nxi"=="%~nx0" (
        set "name=%%~ni"
        setlocal enabledelayedexpansion
        set name1=!name!
        call :lp
        ren "!name!%%~xi" "!nam!%%~xi"
        set "nam="
        endlocal
     )
  )
pause&goto :eof
:lp
if defined name1 (
   set "var=!name1:~,1!"
   if defined !var! set "nam=!nam!!var!"
   set name1=!name1:~1!
   goto lp
)[/code]

pusofalse 发表于 2008-8-5 23:34

看到terse前辈的代码,忽然闪现了一个思路,但立刻消失了,觉得这题肯定有更简单的方法。
只需思考一个问题,如何把字母从这一堆特殊字符中提取出来即可。

pusofalse 发表于 2008-8-6 00:24

写了将近一个小时,做是做出来了,但并不简洁。
[code]@echo off
for %%a in (*.*) do (
if "%%~nxa" neq "%~nx0" (
set "name=%%~na"
call,set name=%%name: =%%
call,set name=%%name:!=%%
setlocal enabledelayedexpansion
for /l %%s in (0 1 9) do set name=!name:%%s=!
set name=!name:%%=!
for %%s in (@ _ # . $ - ^&) do set name=!name:%%s=!
call :lp !name!
echo !nam!%%~xa&set "nam="
endlocal
))
pause&exit/b
:lp
for /f "tokens=1* delims=~" %%l in ("%1") do (
set "n=!n!%%l
if "%%m" neq "" (
call :lp %%m
) else (
for %%a in (a b c d e f g h i j k l m n o p q r s t u v w x y z) do set n=!n:%%a= %%a !
for %%a in (!n!) do if "%%a" geq "a" if "%%a" leq "Z" set nam=!nam!%%a
))[/code]

tjtchly 发表于 2008-8-14 20:20

楼上的没用。不用达到目的。

愚无尽 发表于 2008-8-15 19:45

很有意思的说。。。。

pusofalse 发表于 2008-8-19 09:04

回复 13楼 的帖子

我可是测试了好多遍的,特殊字符无非就是那么几个而已。

dishuo 发表于 2008-8-20 12:45

[quote]原帖由 [i]pusofalse[/i] 于 2008-8-5 23:34 发表 [url=http://bbs.bathome.net/redirect.php?goto=findpost&pid=6666&ptid=1251][img]http://bbs.bathome.net/images/common/back.gif[/img][/url]
看到terse前辈的代码,忽然闪现了一个思路,但立刻消失了,觉得这题肯定有更简单的方法。
只需思考一个问题,如何把字母从这一堆特殊字符中提取出来即可。 [/quote]
根据 pusofalse斑竹的思路,提取字符最方便的工具肯定是正则表达式,批处理命令唯一一个支持正则的就是findstr,能不能用它来提取呢?
测试成功!
满足要求:简洁、通用、效率不至于太低。
特点:通用性很强,只需要修改 findstr 的正则参数就能实现各种功能,举几个例子。
   "[^-!-~0-9a-z]"  保留全角字符(中文、全角标点等)
   "[a-z0-9]"   保留英文字母和数字

[quote]
[font=Fixedsys][color=#000000]@[/color][color=#d50000]echo [/color][color=#000000]off&cls
[/color][color=#d50000]for [/color][color=#000000]/f "tokens=*" %%i [/color][color=#d50000]in [/color][color=#000000]('[/color][color=#d50000]dir [/color][color=#000000]/b/a-d "*.*"') [/color][color=#d50000]do [/color][color=#000000](
    [/color][color=#d50000]if [/color][color=#000000]"%%~nxsi" neq "%~nxs0" (
        [/color][color=#d50000]set [/color][color=#000000]"旧文件名=%%~nxsi"&set "文件名串=%%~ni"&set "新文件名="&set "counter=0"
        [/color][color=#d50000]del [/color][color=#000000]~filenamechar.lst /q>[/color][color=#d50000]nul [/color][color=#000000]2>&1
        setlocal enabledelayedexpansion
        [/color][color=#d50000]call [/color][color=#000000]:split
        [/color][color=#d50000]for [/color][color=#000000]/f "tokens=*" %%n [/color][color=#d50000]in [/color][color=#000000]('findstr "[a-z]" ~filenamechar.lst') [/color][color=#d50000]do set [/color][color=#000000]"新文件名=!新文件名!%%n"
        [/color][color=#d50000]if [/color][color=#000000]"!新文件名!" neq "" (
            [/color][color=#d50000]echo [/color][color=#000000]ren !旧文件名! !新文件名!%%~xi
        ) else (
            [/color][color=#d50000]echo  [/color][color=#000000]^(文件"!旧文件名!"不含字母,不能重命名.^)
        )
        endlocal
    )
)
[/color][color=#d50000]del [/color][color=#000000]~filenamechar.lst /q>[/color][color=#d50000]nul [/color][color=#000000]2>&1
pause&goto :eof

[/color][color=#000080]:split
[/color][color=#d50000]if [/color][color=#000000]"!文件名串:~%counter%,1!" neq "" (
    [/color][color=#d50000]if [/color][color=#000000]"!文件名串:~%counter%,1!" neq " " [/color][color=#d50000]echo [/color][color=#000000]!文件名串:~%counter%,1!>>~filenamechar.lst
    [/color][color=#d50000]set [/color][color=#000000]/a counter+=1
    [/color][color=#d50000]goto [/color][color=#000000]split
)
[/color][color=#d50000]goto [/color][color=#000000]:eof[/color][/font][/quote]

尘丶 发表于 2015-9-27 09:53

[code]@echo off
set "z=a b c d e f g h i j k l m n o p q r s t u v w x y z"
for /f "delims=" %%a in ('dir /b *^|findstr /vc:"%~nx0"') do (
set k=
set wenben=%%~na
set wenjian=%%a
setlocal enabledelayedexpansion
        for /l %%b in (0,1,50) do (
            set zimu=!wenben:~%%b,1!
                for %%c in (!z!) do (
                      if /i "!zimu!"=="%%c" set k=!k!!zimu!
                  )
        )
ren "!wenjian!" "!k!%%~xa"
endlocal
)
pause[/code]

无忧 发表于 2017-5-15 15:45

能不能直接用通配符呢………………
比如*.doc 然后改成你想要的就可以了…………反正也只有唯一的三种文件,不用担心改错……

ai20110304 发表于 2018-9-5 20:47

[b]回复 [url=http://www.bathome.net/redirect.php?goto=findpost&pid=5988&ptid=1251]5#[/url] [i]batman[/i] [/b][code]for /f "tokens=%n% delims=%str% " %%a in ("%var%") [/code]变量引用有误,原文件名字符串中含感叹号包裹,会造成感叹号之间的字母当作变量是为空值不存在。如:一b!a!1235@_ s%#8i  三 c.rar    ----> !a!    最后处理出来是 : bsic.rar
应防止变量值中含感叹号,该这样写:[code]for /f "tokens=%n% delims=%str% " %%a in ("!var!")[/code]测试成功。
感谢5楼提供的处理思路。

ai20110304 发表于 2018-9-5 21:21

[b]回复 [url=http://www.bathome.net/redirect.php?goto=findpost&pid=5968&ptid=1251]2#[/url] [i]pusofalse[/i] [/b]


    在你思路上进行严格地判断改进了下:[code]@echo off
cd /d %~dp0
::思路:通过字母字符范围大小,逐个字符比较,保留英文字母。
for /f "delims=" %%i in ('dir /b /a-d') do (
        ::排除批处理自身
        if "%%~nxi" neq "%~nx0" (       
               
                ::截取文件名,不含扩展名
                set "name=%%~ni" & set "old=%%~nxi"
                ::避免文件名中有感叹号,动态感知变量值的变化
                setlocal enabledelayedexpansion
               
                set "name1=!name!" & call :loop
                echo;!nam!               
                ren "!old!" "!nam!%%~xi"
               
                ::用完一次清除该变量。避免下次使用还有残留值。
                set "nam="       
               
                endlocal
        )
)

pause>nul & goto :eof

:loop
if defined name1 (
        ::逐个截取字符作判断
        set "var=!name1:~0,1!"
        ::忽略大小写,保证值在字母头尾之间
        if /i "!var!" leq "Z" (
                if /i "!var!" geq "A" (
                        ::满足上面两个条件下作字符串拼接,即有效文件名拼接。
                        set "nam=!nam!!var!"
                )
        )
        ::每次循环后,从左往右依次截断字符串。直至把字符串截取完成空。
        set "name1=!name1:~1!"
        goto loop
)


[/code]

qixiaobin0715 发表于 2021-3-10 16:37

[i=s] 本帖最后由 qixiaobin0715 于 2021-3-10 22:01 编辑 [/i]

考虑的还不是太完善:[code]@echo off
for %%a in (*) do (
    if "%%~nxa" neq "%~nx0" (
        set "filename=%%~na"
        set "str=%%a"
        setlocal enabledelayedexpansion
        set "filename=!filename: =!
        for /l %%b in (0,1,50) do (
            set "str1=!filename:~%%b,1!"
            echo,!str1!|findstr [a-z]>nul 2>nul&&set str2=!str2!!str1!
        )
        ren "!str!" "!str2!%%~xa"
        set str2=
        endlocal
    )
)
pause[/code]

页: [1]

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