【问题标题】:Read second parameter of a function into an array将函数的第二个参数读入数组
【发布时间】:2013-11-17 20:19:11
【问题描述】:

我编写了以下代码,完全符合我的要求:

@echo off
setlocal enabledelayedexpansion

set /a i=0
set in="This is line 1", "This is line 2"
for %%h in (%in%) do (
   set /a i+=1
   set "val[!i!]=%%h"
)
set out=
for /l %%n in (1,1,!i!) do (
  set out=!out! !val[%%n]! ^& vbcrlf ^& _)
echo !out:~1,-12!

它获取 %in% 变量的值并将每个逗号分隔的行读取到数组的一个元素中,然后对其进行一些字符串连接并吐出一个新字符串。现在,当我尝试将其转换为函数时,它失败了,因为 %2 被解析为参数。我需要将 %2 解析为具有可变数量值的单个逗号分隔字符串。这个简单的测试不起作用:

call :Test Title "This is line 1","This is line 2" "arg3"
exit /b

:Test arg1 arg2 arg3
set /a i=0
for %%h in (%2) do (
   set /a i+=1
   set "val[!i!]=%%h"
)
set out=
for /l %%n in (1,1,!i!) do (
  set out=!out! !val[%%n]! ^& vbcrlf ^& _)
echo %1 !out:~1,-12! %3
exit /b

我唯一能想到的就是使用 %* 并将分隔符更改为独特的东西,但如果可能的话,我宁愿避免这样做。

【问题讨论】:

    标签: arrays batch-file arguments command-line-arguments


    【解决方案1】:

    1。切换中间参数

    这将单独留下%1,并转移所有中间参数,当没有更多参数时停止,并将最后一个参数留在%3

    @echo off
    setlocal
    call :Test One "Two","Three" Four
    endlocal
    exit /b 0
    
    :Test <Title> <Lines...> <LastArg>
    echo %2
    set "Temp=%4"
    if defined Temp shift /2 & goto Test
    echo %1
    echo %3
    exit /b 0
    

    输出

    "Two"
    "Three"
    One
    Four
    

    2。将字符串放入变量中,并传递变量名

    @echo off
    setlocal EnableDelayedExpansion
    set "String="Two","Three""
    call :Test One String Four
    endlocal
    exit /b 0
    
    :Test <a> <b> <c>
    echo %1
    echo !%2!
    echo %3
    exit /b 0
    

    输出

    One
    "Two","Three"
    Four
    

    这是我想到的前两个解决方案。

    更新

    这是使用内部循环 :__Test 应用于您的代码的 shift 方法

    @echo off
    setlocal EnableDelayedExpansion
    call :Test Title "This is line 1","This is line 2" "arg3"
    endlocal
    exit /b 0
    
    :Test <arg1> <arg2[,...]> <arg3>
    set "i=0"
    :__Test
    set /a "i+=1"
    set "val[!i!]=%2"
    set "tempvar=%4"
    if defined tempvar shift /2 & goto __Test
    set "out="
    for /l %%n in (1,1,!i!) do (
      set out=!out! !val[%%n]! ^& vbcrlf ^& _)
    echo %1 !out:~1,-12! %3
    exit /b 0
    

    【讨论】:

    • 谢谢大卫。 shift 选项似乎是要走的路,但我不知道如何在我的代码中实现它。
    • @MattWilliamson 我用一个例子更新了我的答案。
    • @dbenham 更新示例是否有助于阐明方法 1?我很重视您的输入 dbenham,因为您是批处理文件方面的专家。
    • 好的,我想我理解这个概念了。请注意,这不适用于多个列表参数。我建议通过重新排列参数来简化事情。我会将列表放在最后,以便从 3 开始的所有参数都在列表中,并按照您的建议使用 SHIFT 循环它们。
    • 我现在明白了。我试图在 for 循环内进行转换。谢谢大卫!
    【解决方案2】:

    对于一般解决方案,通过引用传递值(将值存储在变量中并传递变量名称)是最佳选择。这与 David Ruhmann 的第二个选项相同。

    还有另一种方法,但它需要调用者做更多的工作。您可以要求将参数值中的所有引号加倍,然后将整个参数括在另一组引号中。在函数中,将所有"" 替换为" 以获得所需的值。在我学会了通过引用传递值之前,我曾经使用过这种方法。

    @echo off
    setlocal enableDelayedExpansion
    call :Test Title """This is line 1"",""This is line 2""" "arg3"
    exit /b
    
    :Test arg1 arg2 arg3
    set "arg2=%~2"
    set "arg2=%arg2:""="%"
    echo arg1=%1
    echo arg2=%arg2%
    echo arg3=%3
    

    更新

    通过引用传递值是传递包含标记分隔符和引号的复杂值的最佳选择。

    但是 OP 对作为单个参数的值列表并不真正感兴趣,因为使用 FOR 循环将它们拆分。如果任何值包含*?,FOR 循环可能会遇到问题。

    我现在看到,对于这种特殊情况,最好将列表移动到末尾,这样从 3 开始的所有参数都是列表的一部分。然后使用SHIFT /3GOTO 循环读取列表值。这基本上是 David Ruhmann 的选项 1。

    【讨论】:

    • +1 很好的解释和洞察力。也感谢您对我的回答的投入。
    猜你喜欢
    • 2011-03-08
    • 1970-01-01
    • 1970-01-01
    • 2021-12-20
    • 2019-07-15
    • 1970-01-01
    • 1970-01-01
    • 2023-02-06
    • 1970-01-01
    相关资源
    最近更新 更多