2

我有下面的批处理脚本。它应该读取文本文件每一行的第一个字符。就是a到z,应该在对应的文件夹下做一个子文件夹。它是别的东西,它应该在“_other”文件夹中创建。

所以如果我有一个清单:

123test
aaatest
bbbtest

它应该创建:

c:\dirs\_other\123test
c:\dirs\a\aaatest
c:\dirs\b\bbbtest

但由于某种原因,我的最后一个 if/else 不起作用。为什么不?这是脚本:

setlocal EnableDelayedExpansion
set file=c:\klantenlijst.txt
FOR /F "delims=~" %%i IN (!file!) DO (
set var=%%i 
set str=!var:~0,1!
IF !str!==A ( set letter=1 )
IF !str!==B ( set letter=1 )
IF !str!==C ( set letter=1 )
IF !str!==D ( set letter=1 )
IF !str!==E ( set letter=1 )
IF !str!==F ( set letter=1 )
IF !str!==G ( set letter=1 )
IF !str!==H ( set letter=1 )
IF !str!==I ( set letter=1 )
IF !str!==J ( set letter=1 )
IF !str!==K ( set letter=1 )
IF !str!==L ( set letter=1 )
IF !str!==M ( set letter=1 )
IF !str!==N ( set letter=1 )
IF !str!==O ( set letter=1 )
IF !str!==P ( set letter=1 )
IF !str!==Q ( set letter=1 )
IF !str!==R ( set letter=1 )
IF !str!==S ( set letter=1 )
IF !str!==T ( set letter=1 )
IF !str!==U ( set letter=1 )
IF !str!==V ( set letter=1 )
IF !str!==W ( set letter=1 )
IF !str!==X ( set letter=1 )
IF !str!==Y ( set letter=1 )
IF !str!==Z ( set letter=1 )

IF !letter!==1 ( md c:\Dirs\!str!\!var! ) ELSE ( md c:\Dirs\_Other\!var! )

)
4

4 回答 4

5

这是我会这样做的方式:

@echo off
setlocal EnableDelayedExpansion
set letters=ABCDEFGHIJKLMNOPQRSTUVWXYZ
set file=c:\klantenlijst.txt
FOR /F "delims=" %%i IN (%file%) DO (
   set var=%%i
   set str=!var:~0,1!
   for %%a in ("!str!") do if "!letters:%%~a=!" equ "%letters%" set str=_other
   md "c:\dirs\!str!\!var!"
)

上面的程序试图从由所有字母组成的字符串中删除第一个字符;如果结果相同,则第一个字符不是字母。此方法更快,因为它不使用任何外部 .exe 命令。

编辑添加了一些解释

在下面的下一个示例中,我首先编写一个命令,然后编写它的输出。

letters变量包含 26 个字母,即:

echo !letters!
ABCDEFGHIJKLMNOPQRSTUVWXYZ

批处理允许以这种方式替换变量值的一部分:

echo !letters:M=123!
ABCDEFGHIJKL123NOPQRSTUVWXYZ

如果没有给出替换字符串,则原始子字符串将被删除:

echo !letters:M=!
ABCDEFGHIJKLNOPQRSTUVWXYZ

如果原始子字符串包含在另一个变量中,则使用其值实现替换。例如,如果变量有一个字母:

set str=M
echo !letters:%str%=!
ABCDEFGHIJKLNOPQRSTUVWXYZ

另一方面,如果变量没有字母,则新值与原始值相同:

set str=1
echo !letters:%str%=!
ABCDEFGHIJKLMNOPQRSTUVWXYZ

这样,如果您"!letters:%str%=!"比较"%letters%"; 如果结果不同,则 str 变量包含一个字母;否则 str 变量包含非字母字符。

但是,您必须注意 str 变量是在FOR 循环内修改的。这意味着必须使用 DelayedExpansion 替换它的值,但这会导致以下有趣的代码:"!letters:!str!=!"这当然是无效的。修复此细节的方法是!str!通过 FOR 可替换参数更改值,然后在替换子字符串表达式中使用该参数。

您必须注意,先前的替换是由 cmd.exe 处理器立即作为批处理文件的正常处理来实现的。另一方面,为了执行管道的每一端,ECHO !str! | FINDSTR /I "[A-Z]"需要加载 FINDSTR.EXE 文件(大约 30 KB 大小)并执行两个CMD.EXE 副本,并且针对每个名称执行此过程在列表中!. 这意味着这种方法比前一种方法要慢得多,如果名称列表很大,时间差异会很明显。

于 2013-04-13T00:19:40.380 回答
3

您可以使用FINDSTR来测试第一个字符是否为字母:

...
ECHO !str! | FINDSTR /I "[A-Z]" 1>NUL && (
  command to execute if !str! is a letter
) || (
  command to execute if !str! is not a letter
)
...

"[A-Z]"模式匹配任何字母,并且/I开关使匹配不区分大小写。

例如,如果它不是字母,您可以设置str为。_other这样,当使用该值作为应在其中创建子文件夹的文件夹的名称时,您将不再需要任何条件:

...
ECHO !str! | FINDSTR /I "[A-Z]" 1>NUL || (
  SET str=_other
)
MD "c:\Dirs\!str!\!var!"
...

请注意路径周围的双引号MD。当路径包含空格或其他特殊字符时,这是必需的。(感谢@Peter Wright 的说明。)

于 2013-04-12T19:39:16.930 回答
2

Here is another quick way to verify whether a character is a letter.

@echo off
setlocal EnableDelayedExpansion
set file=c:\klantenlijst.txt
for /f "delims=" %%i IN (%file%) do (
   set var=%%i
   set str=!var:~0,1!
   if /i "!str!" geq "A" if /i "!str!" leq "Z" set "str=_other"
   md "c:\dirs\!str!\!var!"
)

One difference with this approach is that non-English letters with diacriticals will also be counted as letters. These non-English letters all have extended ASCII codes greater than 127. This is the same result that Andriy's FINDSTR method gets.

于 2013-04-13T11:48:19.857 回答
1

这不适用于a,仅适用于A

IF !str!==A ( set letter=1 )

将其替换为:

IF /i !str!==A ( set letter=1 )
于 2013-04-12T19:23:07.683 回答