简体   繁体   English

数组索引的双重扩展 Windows 批处理

[英]Double Expansion on Array Index Windows Batch

Inside the for loop I'm trying to access the element at index count in CLs (this line of code: echo !!CLs[!count!]!! ), but I'm not sure how to do this.在 for 循环中,我试图访问CLs中索引count处的元素(这行代码: echo !!CLs[!count!]!! ),但我不知道该怎么做。 I don't really understand how expansion works in this case, so what you see below it me trying something out of no where.我真的不明白在这种情况下扩展是如何工作的,所以你在下面看到的我在不知从哪里尝试一些东西。

@ECHO off
setlocal enableextensions enabledelayedexpansion

SET CLs[0]=#

SET /A count = 0
FOR /F "tokens=5" %%I IN ('some command') DO (
    echo !!CLs[!count!]!! :: THIS LINE
    IF NOT %%I == CLs[!count!] (
        SET /A count += 1
        SET CLs[!count!]=%%I 
    )
)

echo The item is %CLs[10]%
endlocal

Thanks谢谢

According to the post How does the Windows Command Interpreter (CMD.EXE) parse scripts?根据帖子Windows 命令解释器(CMD.EXE)如何解析脚本? (see phase 5), the line echo !!CLs[!count!]!! (参见第 5 阶段),行echo !!CLs[!count!]!! cannot work, because the opening !!不能工作,因为开幕!! are collapsed to a single !都塌成一个! , then !CLs[! , 然后!CLs[! is expanded to an empty string (assuming such variable is not defined), then count is returned literally, then !]!扩展为空字符串(假设未定义此类变量),然后按字面意思返回count ,然后!]! is expanded to an empty string and the final !扩展为一个空字符串和最后一个! is dismissed.被解雇。 Or in other words, delayed expansion cannot be nested.或者换句话说,延迟扩展不能嵌套。

You can use call though to introduce another parsing phase, like this:您可以使用call来引入另一个解析阶段,如下所示:

call echo %%CLs[!count!]%%

The line IF NOT %%I == CLs[.count.] (... ) is wrong, you must expand the right value too. IF NOT %%I == CLs[.count.] (... )行是错误的,您也必须扩展正确的值。 However, call if will not help unfortunately, because if (like for and rem ) is a special command that is recognised by the parser earlier than others, like call .然而,不幸的是, call if并没有帮助,因为if (如forrem )是一个特殊的命令,解析器比其他命令更早地识别它,如call

To work around that you can store the value of !count!要解决这个问题,您可以存储!count! in a for meta-variable, like %%J , for instance, to introduce another parsing phase, and use !CLs[%%J]!for元变量中,例如%%J ,以引入另一个解析阶段,并使用!CLs[%%J]! then, like this:然后,像这样:

set /A "count=0"
for /F "tokens=5" %%I in ('some command') do (
    for %%J in (!count!) do (
        echo !CLs[%%J]!
        if not "%%I" == "!CLs[%%J]!" (
            set /A "count+=1"
            set "CLs[!count!]=%%I"
        )
    )
)

Another yet slower possibility is to put the relevant code into a sub-routine:另一种较慢的可能性是将相关代码放入子例程中:

set /A "count=0"
for /F "tokens=5" %%I in ('some command') do (
    call :SUB !count!
)

goto :EOF


:SUB
    echo !CLs[%~1]!
    if not "%%I" == "!CLs[%~1]!" (
        set /A "count+=1"
        set "CLs[%~1]=%%I"
    )
    goto :EOF

You may also take a look at the post Arrays, linked lists and other data structures in cmd.exe (batch) script about how to deal with such pseudo-arrays.您还可以查看 Arrays 中的帖子cmd.exe(批处理)脚本中的链表和其他数据结构,了解如何处理此类伪数组。

ECHO ------------- START AT %time%

REM <!-- language: lang-dos -->
@ECHO Off
setlocal enableextensions ENABLEDELAYEDEXPANSION

SET "sourcedir=U:\sourcedir"
SET "filename1=%sourcedir%\q58209698.txt"

SET CLs[0]=#
SET /a clscnt[0]=0

SET /A count = 0
FOR /F "tokens=*" %%I IN ('type %filename1%') DO (
 SET "processed="
 FOR /f "tokens=1,2,3delims=[]=" %%a IN ('set cls[') DO IF /i "%%a"=="cls" (
  IF "%%I"=="%%c" (SET /a clscnt[%%b]+=1&SET "processed=y")
 )
 IF not DEFINED processed SET /a count+=1&SET "cls[!count!]=%%I"&SET /a clscnt[!count!]=1
)

FOR /L %%a IN (0,1,%count%) DO ECHO !clscnt[%%a]! times !cls[%%a]!

ENDLOCAL
ECHO -------------------------Second way -----------------
@ECHO Off
setlocal enableextensions ENABLEDELAYEDEXPANSION

SET "sourcedir=U:\sourcedir"
SET "filename1=%sourcedir%\q58209698.txt"

SET CLs[0]=#
SET /a clscnt[0]=0

SET /A count = 0
FOR /F "tokens=*" %%I IN ('type %filename1%') DO (
 SET "processed="
 FOR /L %%a IN (0,1,!count!) DO (
  IF "%%I"=="!cls[%%a]!" (SET /a clscnt[%%a]+=1&SET "processed=y")
 )
 IF not DEFINED processed SET /a count+=1&SET "cls[!count!]=%%I"&SET /a clscnt[!count!]=1
)

FOR /L %%a IN (0,1,%count%) DO ECHO !clscnt[%%a]! times !cls[%%a]!

ENDLOCAL

GOTO :EOF

I used a file named q58209698.txt containing some dummy data for my testing and chose to use the entire data line, having no suitable files where token 5 existed.我使用了一个名为q58209698.txt的文件,其中包含一些用于我的测试的虚拟数据,并选择使用整个数据行,没有合适的文件存在token 5

Note that as a bonus, I've added clscnt - an array of occurence-counts.请注意,作为奖励,我添加了clscnt - 出现计数的数组。

Shown: two separate ways of achieving the aim of finding/counting the unique tokens.显示:实现查找/计算唯一令牌目标的两种不同方法。 Naturally, if the cls array is pre-loaded with the required tokens, then it's basic-programmer's-play to adjust the code to detect/report occurrences of those tokens.自然地,如果cls数组预先加载了所需的令牌,那么基本程序员的工作就是调整代码以检测/报告这些令牌的出现。

The two methods are similar.这两种方法是相似的。 In the first, set is used to list the established variables starting cls[ .首先, set用于列出以cls[开头的已建立变量。 The first if ensures processing only the array-name cls , then either it's a repeat (set prcoessed to a value and increment the occurrences-counter) or it's a new value (when the for...%%a loop ends, processed is still undefined) so record it.第一个if确保仅处理数组名称cls ,然后它是重复的( prcoessed为一个值并增加出现计数器)或者它是一个新值(当for...%%a循环结束时, processed的是仍然未定义)所以记录它。

The second way is more direct, using the value of count to specifically interrogate the values in the cls array.第二种方式更直接,使用count的值专门查询cls数组中的值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM