【问题标题】:How to parse JSon in Pure Batch如何在纯批处理中解析 JSON
【发布时间】:2018-12-13 06:18:08
【问题描述】:

我试图了解批处理文件中的 for 循环如何使用 /F "delims=" 选项但不使用标记遍历所有项目。我尝试了各种方法,但都失败了。首先,我知道还有其他方法可以读取 json 文件,但我只对学习如何在没有任何外部程序 jscript jq 等的情况下以纯批处理方式进行操作感兴趣。 JSon 格式如下所示,但项目数和顺序它们往往会有所不同。

{"SomeVariableName": "SomeString", "SomeVariableName": "SomeString", "SomeVariableName": "SomeString", "SomeVariableName": "SomeString"}
{"SomeVariableName": "SomeString", "SomeVariableName": "SomeString", "SomeVariableName": "SomeString", "SomeVariableName": "SomeString"}
{"SomeVariableName": "SomeString", "SomeVariableName": "SomeString", "SomeVariableName": "SomeString", "SomeVariableName": "SomeString"}
{"SomeVariableName": "SomeString", "SomeVariableName": "SomeString", "SomeVariableName": "SomeString", "SomeVariableName": "SomeString"}
etc

但有时可能只是:

"SomeVariableName2": "SomeString2", "SomeVariableName1": "SomeString1",

例如我已经这样做了:

SetLocal DisableDelayedExpansion
For /F "delims=" %%c (file.json) Do(
REM iterate through each line
  set "Line=%%c"
  setlocal EnableDelayedExpansion
  set CR=CRLFCRLF
  Set "LineChange1=!Line:~1,-1!"
  for %%d in ("!CR!") do set LineChange2=!LineChange1:", "=%%~d!
  for %%e in (!LineChange4:CRLFCRLF= !) do set /a numtkns+=1
  REM but don't know how to insert the above numtkns in for options as it seems to require a function.
  set LineChange3=!LineChange2:": "==!
  set LineChange4=!LineChange3:"=!
  set /A Countr+=1
  REM this leaves this current line stored in variable LineChange4 as SomeVariableName=SomeStringCRLFCRLFSomeVariableName=SomeStringCRLFCRLFSomeVariableName=SomeStringCRLFCRLFSomeVariableName=SomeString
  )

或者,我可以使用换行符代替 CRLFCRLF:

SetLocal DisableDelayedExpansion
For /F "delims=" %%c (file.json) Do(
REM iterate through each line
set "Line=%%c"
setlocal EnableDelayedExpansion
for /f %%d in ('copy /Z "%~dpf0" nul') do (
 set "CR=%%d"
)
Set "LineChange1=!Line:~1,-1!"
for %%e in ("!CR!") do set LineChange2=!LineChange1:", "=%%~e!
set LineChange3=!LineChange2:": "==!
set LineChange4=!LineChange3:"=!
set /A Countr+=1

)

这导致多行存储在变量 LineChange4 中:

SomeVariableName=SomeString
SomeVariableName=SomeString
SomeVariableName=SomeString
SomeVariableName=SomeString

如何遍历每个键值对并将每个值分配给与键同名的变量。我看过另一篇文章,他们确实设置了 var_%SomeVariableName%=SomeString 但它只适用于第一个键值对,我希望它遍历所有项目直到最后一个,即使令牌的数量和它们的顺序不同。

编辑:SomeString 可能是包含各种字符的标题,因此唯一近似已知的值是 SomeVariableName 键,它们往往没有空格。

Edit2:我最初并没有添加,我还使用“Set "LineChange1=!Line:~1,-1!" 来删除通常随 JSon 文件一起提供的花括号。

【问题讨论】:

    标签: json parsing batch-file for-loop token


    【解决方案1】:

    鉴于输入字符串的键 (SomeVariableName) 和值 (SomeString) 部分都不包含 *、?、<、>、",它们真正用引号""括起来,关键部分(SomeVariableName)不包含:,=,值部分(SomeString)不等于序列: + SPACE,以下可以工作:

    @echo off
    rem // Read JSON file line by line:
    for /F "usebackq delims=" %%L in ("file.json") do (
        rem // Store current line string:
        set "LINE=%%L"
        setlocal EnableDelayedExpansion
        rem // Replace key/value separator `": "` by `":"` (remove space):
        set "LINE=!LINE:": "=":"!"
        rem // Trim off opening and closing braces `{`/`}`:
        if defined LINE if "!LINE:~,1!"=="{" set "LINE=!LINE:~1!"
        if defined LINE if "!LINE:~-1!"=="}" set "LINE=!LINE:~,-1!"
        rem // Iterate through key/value pairs (separated by `, `):
        for %%P in (!LINE!) do (
            endlocal
            rem // Split key/value pair:
            for /F "tokens=1* delims=: eol=:" %%Q in ("%%P") do (
                rem // Remove quotes, assign variable (key = value):
                set "%%~Q=%%~R"
            )
            setlocal EnableDelayedExpansion
        )
        endlocal
    )
    

    这种方法通过删除分隔冒号 : 后面的 SPACE 来更改每个键/值对 "SomeVariableName": "SomeString";由于: 不是标准的标记分隔符,与SPACE 和逗号, 不同,标准的for loop 可以将每个键/值对作为单个项进行迭代;然后可以使用for /F loop 在: 处拆分键和值;最后,每个部分的引号""被~ modifier去掉,赋值完成。

    切换delayed expansion 是为了避免在输入字符串中出现感叹号!。

    【讨论】:

    • 实际上 SomeString 可能是一个包含各种字符的标题,因此唯一近似已知的值是 SomeVariableName 键,它们往往没有空格。我已经更新了我的问题,很抱歉忘记添加。
    • SomeVariableName 和 SomeString 都可以包含空格;最近的编辑甚至允许序列冒号后​​跟空格...
    【解决方案2】:

    file.json 或正在下载的数据的格式如下

    {"SomeVariableName1": "SomeString1", "SomeVariableName2": "SomeString2", "SomeVariableName3": "SomeString3", "SomeVariableName4": "SomeString4"}
    {"SomeVariableName1": "SomeString1", "SomeVariableName2": "SomeString2", "SomeVariableName3": "SomeString3", "SomeVariableName4": "SomeString4"}
    {"SomeVariableName1": "SomeString1", "SomeVariableName2": "SomeString2", "SomeVariableName3": "SomeString3", "SomeVariableName4": "SomeString4"}
    {"SomeVariableName1": "SomeString1", "SomeVariableName2": "SomeString2", "SomeVariableName3": "SomeString3", "SomeVariableName4": "SomeString4"}
    

    即使 SomeString 包含空格,以下代码也可以按照 aschipfl 答案中的修改代码工作。

    :: Define a TAB variable
    For /F "delims=" %%A In ('forfiles /p "%~dp0." /m "%~nx0" /c "cmd /c echo(0x09"') Do Set "TAB=%%A"
    
    rem // also works for ('something that downloads json content')
    For /F "delims=" %%c In ('file.json') Do (
        REM // Store current line string:
        Set "LINE=%%c"
        SetLocal EnableDelayedExpansion
        REM // Replace beginning and ending curly brackets:
        Set "LineChange1=!Line:~1,-1!"
        REM // Replace key/value separator ": " by ":" (remove space):
        Set "LineChange2=!LineChange1:": "=":"!"
        REM // Replace CSV ", " with TSV "TAB" (remove space):
        Set "LineChange3=!LineChange2:", "="%TAB%"!"
        REM // Iterate through key/value pairs (separated by Tab):
        For %%P In (!LineChange3!) Do (
            EndLocal
            REM // Split key/value pair:
            For /F "tokens=1* delims=: eol=:" %%Q In ("%%P") Do (
                REM // Remove quotes, assign variable (key = value):
                Set "var_%%~Q=%%~R"
            )
            SetLocal EnableDelayedExpansion
        )
    @Echo SomeVariableName1=!var_SomeVariableName1!>>Datafile.txt
    @Echo SomeVariableName3=!var_SomeVariableName3!>>Datafile.txt
    )
    

    【讨论】:

    • 不需要用 TAB 替换 ,+SPACE,因为 SPACE、TAB、, 以及 ;、= 是等效的标记分隔符...大括号应该已经在问题中提到了......
    • 是的,当我花了这么多时间试图弄清楚我只是以这种方式发布问题后发布问题时,我太累了,因为这并不是我真正关心的问题。我不确定为什么您发布的代码不能按原样工作,但在用选项卡替换后它确实如此。我是批处理的新手,所以我会把它留给其他人来找出原因并留下这篇文章,以防有人从中受益。如果您想使用我正在处理的 json 文件类型对其进行测试,您可以使用 --dump-json 从 youtube-dl cli 获取它。非常感谢您的帮助。
    【解决方案3】:

    另一种更简单的方法:

    @echo off
    setlocal EnableDelayedExpansion
    
    rem Read the lines of JSon file, removing braces
    for /F "delims={}" %%a in (file.json) do (
       set "line=%%~a"
       rem Process each pair of "variable": "string" values
       for %%b in ("!line:": "==!") do echo SET %%b
    )
    

    使用这个输入文件:

    {"SomeVariableName1": "Some String 1", "SomeVariableName2": "Some&String<2", "SomeVariableName3": "Some>String|3", "SomeVariableName4": "Some  String  4"}
    {"SomeVariableName1": "SomeString1", "SomeVariableName2": "SomeString2", "SomeVariableName3": "SomeString3", "SomeVariableName4": "SomeString4"}
    {"SomeVariableName1": "SomeString1", "SomeVariableName2": "SomeString2", "SomeVariableName3": "SomeString3", "SomeVariableName4": "SomeString4"}
    {"SomeVariableName1": "SomeString1", "SomeVariableName2": "SomeString2", "SomeVariableName3": "SomeString3", "SomeVariableName4": "SomeString4"}
    

    ...这是输出:

    SET "SomeVariableName1=Some String 1"
    SET "SomeVariableName2=Some&String<2"
    SET "SomeVariableName3=Some>String|3"
    SET "SomeVariableName4=Some  String  4"
    SET "SomeVariableName1=SomeString1"
    SET "SomeVariableName2=SomeString2"
    SET "SomeVariableName3=SomeString3"
    SET "SomeVariableName4=SomeString4"
    SET "SomeVariableName1=SomeString1"
    SET "SomeVariableName2=SomeString2"
    SET "SomeVariableName3=SomeString3"
    SET "SomeVariableName4=SomeString4"
    SET "SomeVariableName1=SomeString1"
    SET "SomeVariableName2=SomeString2"
    SET "SomeVariableName3=SomeString3"
    SET "SomeVariableName4=SomeString4"
    

    【讨论】:

    • 不错的一个!尽管它不允许{ 和} 出现在任何名称/字符串中;无论如何 +1...
    【解决方案4】:

    使用 Vasil Arnaudov 的脚本 https://github.com/npocmaka/batch.scripts/blob/master/hybrids/jscript/edit.json.bat 您可以编辑多级 JSON:

    正常.json:

    { "solo": "Solo value", "level1": { "name": "Name1", "version": "04.21", "level2": { "name": "Name2", "code": "da" } }, "single": "Single value" }
    

    跑步:

    edit.json.bat normal.json level1.level2.name "name of level 2"
    

    会给你:

    {"solo":"Solo value","level1":{"name":"Name1","version":"04.21","level2":{"name":"name of level 2","code":"da"}},"single":"Single value"}
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-07-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-22
      • 2018-12-18
      • 2019-02-03
      相关资源
      最近更新 更多