在cmd /批处理中逐字符循环字符串?

时间:2019-02-13 15:45:01

标签: batch-file cmd

我希望摆脱特定目录中文件夹名称中的所有特殊字符。

我当时想我可以将每个字符转换为它的ASCII字符值,如果它不在“普通”字符范围内,我将替换它。

我找不到任何可以显示如何遍历字符串中每个字符的东西。

for /d %%i in (C:\temp\*) do (
    echo before %%~ni
    for CHAR in %%~ni do (
        if CHAR < 33 || CHAR > 126 (
            CHAR = 95
        )
    )
    echo after %%~ni
)
echo Ende

3 个答案:

答案 0 :(得分:0)

这将不会生成重复的目录名称。这会遍历目录名称,并且仅允许字母,数字,下划线和空格。其他所有内容都变成“-”。要更改允许的字符,请在-match之后更改正则表达式。

当您确信重命名将按照您的意愿进行时,请从-WhatIf cmdlet中删除Rename-Item

powershell.exe -NoLogo -NoProfile -Command ^
    "Get-ChildItem | " ^
        "Where-Object { $_.PSIsContainer } | " ^
        "ForEach-Object { " ^
            "$a = $_.Name.ToCharArray(); " ^
            "$s = $null; " ^
            "foreach ($c in $a) { " ^
                "if ($c -match '[\w ]') { $s += $c} else { $s += '-'} " ^
            "} "^
            "if ($s -ne $_.Name) { " ^
                "Rename-Item -Path $_.FullName -NewName $s -WhatIf " ^
            "} " ^
        "}"

自然,如果编写PowerShell脚本,这会更容易。

Get-ChildItem |
    Where-Object { $_.PSIsContainer } |
    ForEach-Object {
        $a = $_.Name.ToCharArray()
        $s = $null
        foreach ($c in $a) {
            if ($c -match '[\w ]') { $s += $c} else { $s += '-'}
        }
        if ($s -ne $_.Name) {
            Rename-Item -Path $_.FullName -NewName $s -WhatIf
        }
    }

答案 1 :(得分:0)

使用CMD和Powershell组合的简单解决方案

@echo off
SETLOCAL ENABLEDELAYEDEXPANSION
set POWERSHELL=c:\windows\system32\windowsPowerShell\v1.0\powershell

PATH=C:\
echo %PATH%

for /F %%I in ('dir /A:-D /b %PATH%') DO (
    set STR=%%I
    echo !STR!
    :loop
        set CH=!STR:~0,1!
        echo Character is: !CH!

        for /F "usebackq" %%F in (`!POWERSHELL! [int][char]"'!CH!'"`) DO (set VAL=%%F)
        echo ascii value: !VAL!

        set STR=!STR:~1!
        if "!STR!" == "" (goto end) 
    goto loop
)

:end
echo Done!

答案 2 :(得分:0)

我决定提供使用PowerShell 2.0 (使其与Windows 7系统兼容)的批处理文件版本。它通过使用十六进制字符而不是您在问题中提到的十进制字符来工作。 ASCII 33 = Hex 21ASCII 126 = Hex 7E ,我将其替换为下划线字符 _ ,例如您的示例:

批处理文件

@PowerShell -NoP "GCI 'C:\temp'|"^
 "?{$_.PSIsContainer -And $_.BaseName -Match '[^\x21-\x7E]+'}|"^
 "%%{RnI $_.FullName ($_.BaseName -Replace '[^\x21-\x7E]+', '_') -Wh}"
@Pause

上面使用了-WhatIf(简称为-Wh,向您展示了如果不实际操作会发生什么情况。如果您对输出感到满意,则可以删除 -Wh和最后一行@Pause

当然,您可能会忘记从批处理文件运行它,而直接将其作为 PowerShell脚本(简称为帮助您了解正在发生的事情):< / p>

Get-ChildItem 'C:\temp' |
    Where-Object {
        $_.PSIsContainer -And $_.BaseName -Match '[^\x21-\x7E]+'
    } | ForEach-Object {
        Rename-Item -Path $_.FullName -NewName ($_.BaseName -Replace '[^\x21-\x7E]+', '_')
    }

与批处理文件示例不同,我没有包含-WhatIf语句,因此请注意运行该语句将重命名目录


注意

这些解决方案未考虑任何已经包含您希望重命名的名称的现有目录。如果这种情况很可能存在,那么您将需要改进我所发布的内容。


[编辑/]

如果您只想查看现有格式和替换格式的目录名称,而实际上不进行任何重命名,则可能希望使用其他布局。

这只是以一种不同的颜色将它们显示在另一个之上:

@PowerShell -NoP "GCI 'C:\temp\test'|"^
 "?{$_.PSIsContainer -And $_.BaseName -Match '[^\x21-\x7E]+'}|"^
      "%%{Write-Host($_.BaseName)-F Red;Write-Host($_.BaseName -Replace '[^\x21-\x7E]+', '_')-F Cyan}"
@Pause

.ps1版本:

Get-ChildItem 'C:\temp\test' |
    Where-Object {
        $_.PSIsContainer -And $_.BaseName -Match '[^\x21-\x7E]+'
    } | ForEach-Object {
        Write-Host $_.BaseName -ForegroundColor Red
        Write-Host ($_.BaseName -Replace '[^\x21-\x7E]+', '_') -ForegroundColor Cyan
    }