好的...澄清问题。这是原始的“kludgey”代码 - 实际代码,而不是简化的说明性示例(我让我的 cmets 解释它在做什么):
:: 'call :array_load pathname [arry:val]'
:: INPUT - 1-2 parameters: datafile path and optional condition
:: RESULT - sets up arrays & UBOUNDs (array[0])
:: Read a datafile (identified in the first parameter). This file has an array
:: definition line and a number of data lines. The array definition line starts
:: with 'arry ' and lists the arrays to be populated from the data statements.
:: Data statements list the information to be put into the arrays, in the same
:: order as the arrays listed in the arry statement.
:: An optional second parameter causes only lines that have the value given for
:: that array to be included (ex: 'ZIP:23456' causes only addresses in zipcode
:: 23456 to be read).
:: The arry statement can be anywhere in the file. The data statements are read
:: in the order of appearance.
:: The Upper boundary (UBOUND) is stored in [0]
:array_load
set _DATAFILE=%1
set _COND=%2
if not exist %_DATAFILE% (
echo [E] - {array_load} Array datafile %1 not found. Aborting run.
pause
exit
)
:: Detect and set up for use of the second parameter.
if defined _COND for /f "tokens=1-2 delims=:" %%a in ("%_COND%") do (set _ARY=%%a&set _VAL=%%b)
:: Gets the list of arrays from the "arry" statement
for /f "usebackq tokens=1,*" %%a in (`findstr "^arry " %_DATAFILE%`) do ( set "ARRAYLIST=%%b")
:: Set up the array names and prep for the second loop. The "tokens" var sets
:: up to read the columns in the data statements. Token 1 is always "data" and
:: is skipped.
set ndx=1
for %%a in (%ARRAYLIST%) do (
set COL!ndx!=%%a
set /a ndx+=1
)
:: "TOKENS" is not a mathematical calculation - it is a range definition used
:: in the next FOR statement. Do not add /a to the set!
set TOKENS=2-%ndx%
set /a ARYCOUNT=ndx-1
:: Read the data statements into the arrays. The "if defined" increments the
:: index for the next read only if there is no condition or the condition is
:: met. The "for" inside this "if" exists because the condition can't be tested
:: without it.
set ndx=1
for /f "usebackq tokens=%TOKENS%" %%a in (`findstr "^data " %_DATAFILE%`) do (
set !COL1![!ndx!]=%%a
if %ARYCOUNT% GEQ 2 set !COL2![!ndx!]=%%b
if %ARYCOUNT% GEQ 3 set !COL3![!ndx!]=%%c
if %ARYCOUNT% GEQ 4 set !COL4![!ndx!]=%%d
if %ARYCOUNT% GEQ 5 set !COL5![!ndx!]=%%e
if %ARYCOUNT% GEQ 6 set !COL6![!ndx!]=%%f
if %ARYCOUNT% GEQ 7 set !COL7![!ndx!]=%%g
if defined _COND (
for /f "usebackq" %%x in (`echo %_ARY%[!ndx!]`) do set RES=!%%x!
if !RES!==%_VAL% set /a ndx+=1
) else (
set /a ndx+=1
)
set /a !COL1![0]=!ndx!-1
if %ARYCOUNT% GEQ 2 set /a !COL2![0]=!ndx!-1
if %ARYCOUNT% GEQ 3 set /a !COL3![0]=!ndx!-1
if %ARYCOUNT% GEQ 4 set /a !COL4![0]=!ndx!-1
if %ARYCOUNT% GEQ 5 set /a !COL5![0]=!ndx!-1
if %ARYCOUNT% GEQ 6 set /a !COL6![0]=!ndx!-1
if %ARYCOUNT% GEQ 7 set /a !COL7![0]=!ndx!-1
)
exit /b
此例程加载一组与索引相关的数组。这是一个示例数据文件。我将 cmets 留在文件中以帮助解释发生了什么。例程实际上只使用了“arry”和“data”行。
To be REFERENCED by :array_load function
The line starting with "arry " contains the names of the arrays to be
filled from the data provided. Columns do not need to line up; extra spaces
are ignored. There is a maximum of six arrays without revisiting the
:array_load functions. ANY change of the "arry" names requires revisiting
the code that uses them!
All Data lines must begin with "data ", and NO other lines can start that
way! The keywords "data" and "arry" are case-sensitive and must be followed
by a space.
All lines that do NOT start with "arry " or "data " are comments.
arry FIRST LAST PHONE ZIP
data Joe Wilson 202-417-2742 20122
data John Doe 209-659-2482 10523
data Susan Doe 209-659-2482 10523
data Bill Johnson 619-384-2582 53737
data Cindy Wahler 301-724-7496 20933
data Rebecca Tannis 410-473-2748 20536
This will result in FIRST[0]=6, FIRST[1]=Joe, LAST[0]=6, LAST[1]=Wilson, etc
on up to FIRST[6]=Rebecca ... ZIP[6]=20536 (all the [0]'s = 6, as the array size)
上面的代码可以工作(并且相当快),除非最后一行被条件检查排除在外,在这种情况下最后一行实际上并没有被排除。如果数组数量超过 if ... geq .. %%... 语句的数量,也必须对其进行编辑。
我想:1) 修复最后一行排除错误,2) 删除许多 IF 以实现数组计数的灵活性,3) 使其更快。
这就是我现在正在修补的东西。它确实是#2,我希望它在我完成该部分时能够做到#1,但它在#3 上失败了——FAR 慢得多。在这台计算机上,处理这个仅包含 4 个数组的 6 个值的列表需要 20-30 秒 - 我的实际数据文件大约有 110 行,每行 7 个值,21 行,每行 5 个。
:array_load
set _DATAFILE=%1
set _FILTER=
if not exist %_DATAFILE% (
echo [E] - {array_load} Array datafile %1 not found. Aborting run.
pause
exit /b
)
if not "%2"=="" set _FILTER=%2
:: Gets the list of arrays from the "arry" statement
for /f "usebackq tokens=1,*" %%a in (`findstr "^arry " %_DATAFILE%`) do ( set "ARRAYLIST=%%b")
:: Set up the array names and prep for the second loop.
set ndx=1
for %%a in (%ARRAYLIST%) do (
set COL[!ndx!]=%%a
set /a ndx+=1
)
set /a ARYCNT=ndx-=1
:: Token 1 is always "data" and is skipped.
set ndx=1
for /f "usebackq tokens=1,*" %%a in (`findstr "^data " %_DATAFILE%`) do (
set _LN=%%b
for /l %%x in (1,1,%ARYCNT%) do (
set ARY=!COL[%%x]!
call :array_load_inner %%x
)
set /a ndx+=1
)
exit /b
:array_load_inner
for /f "tokens=%1" %%z in ("!_LN!") do set !ARY![!ndx!]=%%z
set /a !ARY![0]=!ndx!
exit /b
那么,这会让你和我一样眼花缭乱吗? :)
上面的任何一个例程都是一个“答案”,而不是我想要的那个 - 第一个是我的起点,并且在原始问题的范围内起作用,其中不包括对数组或包含的引用。第二个太慢了,不可行。如果我不处理数组,@Stephan 答案会起作用。很抱歉将此材料放入“答案”块 - 它对于评论来说太大了(我想我应该从一开始就包含原始完整代码,而不是试图将示例代码保持在“最小公分母”,所以说话)。对不起...