找回密码
 注册
搜索
[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
查看: 67223|回复: 15

[文本处理] 【已解决】求助批处理从一堆文本文件中提取关键词写到csv中

[复制链接]
发表于 2024-2-25 18:38:06 | 显示全部楼层 |阅读模式
本帖最后由 zhengwei007 于 2024-2-27 09:07 编辑

我有几百个这样的xml文档,文档中是以<item>开头,</item>结尾的,想通过批处理将里面内容整理出来,XML内容如下:
  1.   <item id="3" type="Weapon" name="宽剑">
  2.     <set name="icon" val="icon.weapon_broad_sword_i00" />
  3.     <set name="default_action" val="equip" />
  4.     <set name="weapon_type" val="sword" />
  5.     <set name="bodypart" val="rhand" />
  6.     <set name="random_damage" val="10" />
  7.     <set name="attack_range" val="40" />
  8.     <set name="damage_range" val="0;0;40;120" />
  9.     <set name="immediate_effect" val="1" />
  10.     <set name="material" val="steel" />
  11.     <set name="weight" val="1590" />
  12.     <set name="price" val="9600" />
  13.     <set name="soulshots" val="1" />
  14.     <set name="spiritshots" val="1" />
  15.     <for>
  16.       <set order="0x08" stat="pAtk" val="11" />
  17.       <set order="0x08" stat="mAtk" val="9" />
  18.       <set order="0x08" stat="rCrit" val="8" />
  19.       <set order="0x08" stat="pAtkSpd" val="379" />
  20.     </for>
  21.   </item>
  22.   <item id="4" type="Weapon" name="木棒">
  23.     <set name="icon" val="icon.weapon_club_i00" />
  24.     <set name="default_action" val="equip" />
  25.     <set name="weapon_type" val="blunt" />
  26.     <set name="bodypart" val="rhand" />
  27.     <set name="random_damage" val="20" />
  28.     <set name="attack_range" val="40" />
  29.     <set name="damage_range" val="0;0;40;120" />
  30.     <set name="immediate_effect" val="1" />
  31.     <set name="material" val="wood" />
  32.     <set name="weight" val="1870" />
  33.     <set name="price" val="590" />
  34.     <set name="soulshots" val="1" />
  35.     <set name="spiritshots" val="1" />
  36.     <for>
  37.       <set order="0x08" stat="pAtk" val="8" />
  38.       <set order="0x08" stat="mAtk" val="6" />
  39.       <set order="0x08" stat="rCrit" val="4" />
  40.       <add order="0x10" stat="accCombat" val="4.75" />
  41.       <set order="0x08" stat="pAtkSpd" val="379" />
  42.     </for>
  43.   </item>
  44.   </item>
  45.   <item id="1201" type="EtcItem" name="信仰凭证">
  46.     <set name="icon" val="icon.accessary_earing_of_wisdom_i00" />
  47.     <set name="immediate_effect" val="1" />
  48.     <set name="material" val="steel" />
  49.     <set name="is_tradable" val="false" />
  50.     <set name="is_dropable" val="false" />
  51.     <set name="is_sellable" val="false" />
  52.     <set name="is_depositable" val="false" />
  53.     <set name="is_stackable" val="true" />
  54.     <set name="is_questitem" val="true" />
  55.   </item>
复制代码
我已经将文件上传到网盘,大概意思如下:
1、将每个name拿出来,值拿出来列到文档中。
2、遇到0x0几的直接pass不要。
3、遇到新的没有的name,直接往表格最后增加新列。
4、标题列可能会很多,但没关系,一直往后排就行了。
按照上面的3个例子,输出结果举例:
  1. id        name        icon        default_action        weapon_type        bodypart        random_damage        attack_range        damage_range        immediate_effect        material        weight        price        soulshots        spiritshots        pAtk        mAtk        rCrit        pAtkSpd        accCombat        type        is_tradable        is_dropable        is_sellable        is_depositable        is_stackable        is_questitem
  2. 3        宽剑        icon.weapon_broad_sword_i00        equip        sword        rhand        10        40        0;0;40;120        1        steel        1590        9600        1        1        11        9        8        379                                                               
  3. 4        木棒        icon.weapon_club_i00        equip        blunt        rhand        20        40        0;0;40;120        1        wood        1870        590        1        1        8        6        4                4.75                                                       
  4. 1201        信仰凭证        icon.accessary_earing_of_wisdom_i00                                                        1        steel                                                                                EtcItem        FALSE        FALSE        FALSE        FALSE        FALSE        FALSE
复制代码
文件我打包了,请大佬帮忙看看。
链接:https://pan.baidu.com/s/1eIJ1l6VcI8OmFoyFJwvO-Q
提取码:x4jk
--来自百度网盘超级会员V9的分享
发表于 2024-2-26 08:59:28 | 显示全部楼层
本帖最后由 czjt1234 于 2024-2-26 09:18 编辑
  1. rem 另存为 ANSI 编码 的 bat
  2. ' & cls & %windir%\SysWOW64\CScript.exe /nologo /e:vbscript "%~f0" & pause & exit

  3. Option Explicit
  4. Dim oWshShell, oFSO, oTextStream, oDOMDocument, oXMLDOMElement, oConnection, oRecordset, s, t

  5. Const PATH = "C:\Users\Administrator\Desktop\items"
  6. Const OUT  = "C:\Users\Administrator\Desktop\items\输出.txt"

  7. wsh.Echo Now()
  8. Set oWshShell    = CreateObject("WScript.Shell")
  9. Set oFSO         = CreateObject("Scripting.FileSystemObject")
  10. Set oTextStream  = oFSO.OpenTextFile(OUT, 2, True)
  11. Set oDOMDocument = CreateObject("Msxml2.DOMDocument")
  12. Set oConnection  = CreateObject("ADODB.Connection")
  13. Set oRecordset   = CreateObject("ADODB.Recordset")

  14. s = oFSO.BuildPath(PATH, "temp.mdb")
  15. If oFSO.FileExists(s) Then oFSO.DeleteFile s, True
  16. s = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & s
  17. CreateObject("ADOX.Catalog").Create s
  18. oConnection.Open s
  19. oConnection.Execute "CREATE TABLE list(id INT PRIMARY KEY, name VARCHAR)"

  20. t = "|"
  21. For Each s In oFSO.GetFolder(PATH).Files
  22.     If LCase(oFSO.GetExtensionName(s)) = "xml" Then Call k(s.Path)
  23. Next
  24. oRecordset.CursorLocation = 3    'adUseClient
  25. oRecordset.Open "SELECT * FROM list ORDER BY id ASC", oConnection
  26. s = ""
  27. For t = 0 To oRecordset.Fields.Count - 1
  28.     s = s & oRecordset(t).Name & vbTab
  29. Next
  30. s = Left(s, Len(s) - 1) & vbCrLf
  31. Do Until oRecordset.EOF = True
  32.     For t = 0 To oRecordset.Fields.Count - 1
  33.         s = s & oRecordset(t).Value & vbTab
  34.     Next
  35.     s = Left(s, Len(s) - 1) & vbCrLf
  36.     If Len(s) >= 2048 Then
  37.         oTextStream.Write s
  38.         s = ""
  39.     End If
  40.     oRecordset.MoveNext()
  41. Loop
  42. If s <> "" Then oTextStream.Write s
  43. oRecordset.Close()
  44. oConnection.Close()
  45. oTextStream.Close()

  46. s = oFSO.BuildPath(PATH, "temp.mdb")
  47. If oFSO.FileExists(s) Then oFSO.DeleteFile s, True
  48. wsh.Echo Now()
  49. wsh.Echo "ok"

  50. Sub k(ByVal s)
  51.     Dim i, j, m
  52.     oDOMDocument.Load s
  53.     Set oXMLDOMElement = oDOMDocument.documentElement
  54.     For Each i In oXMLDOMElement.SelectNodes("item[@id and @name]")
  55.         oConnection.Execute "INSERT INTO list(id, name) VALUES(" & i.getAttribute("id") & ", '" & i.getAttribute("name") & "')"
  56.         m = "UPDATE list SET "
  57.         For Each j In i.SelectNodes("set[@name and @val]")
  58.             If InStr(1, t, "|" & j.getAttribute("name") & "|", vbTextCompare) = 0 Then
  59.                 oConnection.Execute "ALTER TABLE list ADD COLUMN [" & j.getAttribute("name") & "] VARCHAR"
  60.                 t = t & j.getAttribute("name") & "|"
  61.             End If
  62.             If InStr(1, m, "[" & j.getAttribute("name") & "]", vbTextCompare) = 0 Then   '处理异常文件 id = 20994
  63.                 m = m & "[" & j.getAttribute("name") & "] = """ & j.getAttribute("val") & """, "
  64.             End If
  65.         Next
  66.         oConnection.Execute Left(m, Len(m) - 2) & " WHERE id = " & i.getAttribute("id")
  67.     Next
  68. End Sub
复制代码
 楼主| 发表于 2024-2-26 10:19:44 | 显示全部楼层
本帖最后由 zhengwei007 于 2024-2-26 10:20 编辑
czjt1234 发表于 2024-2-26 08:59


    <for>
      <set order="0x08" stat="pAtk" val="8" />
      <set order="0x08" stat="mAtk" val="6" />
      <set order="0x08" stat="rCrit" val="4" />
      <add order="0x10" stat="accCombat" val="4.75" />
      <set order="0x08" stat="pAtkSpd" val="379" />
    </for>
请问这些数据没读取,0x0*这些不要,但后面的stat=是要的,patk,matk这些是字段名,把这些字段当成“name=”就好了。
发表于 2024-2-26 10:26:18 | 显示全部楼层
<add 这行算不算?
发表于 2024-2-26 10:39:33 | 显示全部楼层
回复 2# czjt1234


    您这是批处理吗? 好像是vba吧, ,而且这oFSO.GetFolder(PATH).Files 好像连vba都不是
发表于 2024-2-26 10:55:14 | 显示全部楼层
回复 5# likeyou32


是用BAT调用的VBS
http://bbs.bathome.net/thread-4610-1-1.html
 楼主| 发表于 2024-2-26 10:59:53 | 显示全部楼层
回复 4# czjt1234

都算,只是不要前面的order,你就把代码看成 <add stat="accCombat" val="4.75" />,字段是accCombat,值是4.75
发表于 2024-2-26 12:17:26 | 显示全部楼层
  1.      <set order="0x08" stat="pAtk" val="207" />
  2.       <set order="0x08" stat="mAtk" val="157" />
  3.       <set order="0x08" stat="rCrit" val="4" />
  4.       <add order="0x10" stat="accCombat" val="4.75" />
  5.       <set order="0x08" stat="pAtkSpd" val="325" />
  6.       <enchant val="0" order="0x0C" stat="pAtk" />
  7.       <enchant val="0" order="0x0C" stat="mAtk" />
复制代码

最后两行也算吗?
 楼主| 发表于 2024-2-26 12:45:52 | 显示全部楼层
都算,stat的值就是列表标题,val就是值。
发表于 2024-2-26 13:26:40 | 显示全部楼层
  1. rem 另存为 ANSI 编码 的 bat
  2. ' & cls & %windir%\SysWOW64\CScript.exe /nologo /e:vbscript "%~f0" & pause & exit

  3. Option Explicit
  4. Dim oWshShell, oFSO, oTextStream, oDOMDocument, oXMLDOMElement, oConnection, oRecordset, s, t

  5. Const PATH = "C:\Users\Administrator\Desktop\items"
  6. Const OUT  = "C:\Users\Administrator\Desktop\items\输出.txt"

  7. wsh.Echo Now()
  8. Set oWshShell    = CreateObject("WScript.Shell")
  9. Set oFSO         = CreateObject("Scripting.FileSystemObject")
  10. Set oTextStream  = oFSO.OpenTextFile(OUT, 2, True)
  11. Set oDOMDocument = CreateObject("Msxml2.DOMDocument")
  12. Set oConnection  = CreateObject("ADODB.Connection")
  13. Set oRecordset   = CreateObject("ADODB.Recordset")

  14. s = oFSO.BuildPath(PATH, "temp.mdb")
  15. If oFSO.FileExists(s) Then oFSO.DeleteFile s, True
  16. s = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & s
  17. CreateObject("ADOX.Catalog").Create s
  18. oConnection.Open s
  19. oConnection.Execute "CREATE TABLE list(id INT PRIMARY KEY, name VARCHAR)"

  20. t = "|"
  21. For Each s In oFSO.GetFolder(PATH).Files
  22.     If LCase(oFSO.GetExtensionName(s)) = "xml" Then Call k(s.Path)
  23. Next

  24. oRecordset.CursorLocation = 3    'adUseClient
  25. oRecordset.Open "SELECT * FROM list ORDER BY id ASC", oConnection
  26. s = ""
  27. For t = 0 To oRecordset.Fields.Count - 1
  28.     s = s & oRecordset(t).Name & vbTab
  29. Next
  30. s = Left(s, Len(s) - 1) & vbCrLf
  31. Do Until oRecordset.EOF = True
  32.     For t = 0 To oRecordset.Fields.Count - 1
  33.         s = s & oRecordset(t).Value & vbTab
  34.     Next
  35.     s = Left(s, Len(s) - 1) & vbCrLf
  36.     If Len(s) >= 2048 Then
  37.         oTextStream.Write s
  38.         s = ""
  39.     End If
  40.     oRecordset.MoveNext()
  41. Loop
  42. If s <> "" Then oTextStream.Write s
  43. oRecordset.Close()
  44. oConnection.Close()
  45. oTextStream.Close()

  46. s = oFSO.BuildPath(PATH, "temp.mdb")
  47. If oFSO.FileExists(s) Then oFSO.DeleteFile s, True
  48. wsh.Echo Now()
  49. wsh.Echo "ok"

  50. Sub k(ByVal s)
  51.     Dim i, j, m
  52.     oDOMDocument.Load s
  53.     Set oXMLDOMElement = oDOMDocument.documentElement
  54.     For Each i In oXMLDOMElement.SelectNodes("item[@id and @name]")
  55.         oConnection.Execute "INSERT INTO list(id, name) VALUES(" & i.getAttribute("id") & ", '" & i.getAttribute("name") & "')"
  56.         m = "UPDATE list SET "
  57.         For Each j In i.SelectNodes(".//*[@val]")
  58.             If Not IsNull(j.getAttribute("name")) Then
  59.                 If InStr(1, t, "|" & j.getAttribute("name") & "|", vbTextCompare) = 0 Then
  60.                     oConnection.Execute "ALTER TABLE list ADD COLUMN [" & j.getAttribute("name") & "] VARCHAR"
  61.                     t = t & j.getAttribute("name") & "|"
  62.                 End If
  63.                 If InStr(1, m, "[" & j.getAttribute("name") & "]", vbTextCompare) = 0 Then   '处理异常文件 id = 20994
  64.                     m = m & "[" & j.getAttribute("name") & "] = """ & j.getAttribute("val") & """, "
  65.                 End If
  66.             End If
  67.             If Not IsNull(j.getAttribute("stat")) Then
  68.                 If InStr(1, t, "|" & j.getAttribute("stat") & "|", vbTextCompare) = 0 Then
  69.                     oConnection.Execute "ALTER TABLE list ADD COLUMN [" & j.getAttribute("stat") & "] VARCHAR"
  70.                     t = t & j.getAttribute("stat") & "|"
  71.                 End If
  72.                 If InStr(1, m, "[" & j.getAttribute("stat") & "]", vbTextCompare) = 0 Then
  73.                     m = m & "[" & j.getAttribute("stat") & "] = """ & j.getAttribute("val") & """, "
  74.                 End If
  75.             End If
  76.         Next
  77.         oConnection.Execute Left(m, Len(m) - 2) & " WHERE id = " & i.getAttribute("id")
  78.     Next
  79. End Sub
复制代码
发表于 2024-2-26 13:58:14 | 显示全部楼层
  1. @echo off
  2. rem 批处理保存为utf-8编码格式
  3. chcp 65001 >nul
  4. cd /d "%~dp0"
  5. for %%i in (*.xml) do (
  6.         for /f usebacktokens^=1-6delims^=^" %%a in ("%%i") do (
  7.                 if "%%a" equ "    <set name=" (
  8.                         set #"%%b"=,
  9.                 ) else if "%%c" equ " stat=" (
  10.                         set #"%%d"=,
  11.                 ) else if "%%e" equ " stat=" (
  12.                         set #"%%f"=,
  13.                 )
  14.         )
  15. )
  16. (
  17.         set /p=id,type,name<nul
  18.         for /f "tokens=1 delims=#=" %%a in ('set #') do set /p=,%%~a<nul
  19.         echo=
  20. )>out.csv
  21. for %%i in (*.xml) do (
  22.         set /a n+=1
  23.         call echo 正在处理第 [%%n%%] 个
  24.         (for /f usebacktokens^=1-6delims^=^" %%a in ("%%i") do (
  25.                 if "%%a" equ "  <item id=" (
  26.                         setlocal enabledelayedexpansion
  27.                         set str=%%b,%%d,%%f
  28.                 ) else if "%%a" equ "    <set name=" (
  29.                         set #"%%b"=%%d
  30.                 ) else if "%%c" equ " stat=" (
  31.                         set #"%%d"=%%f
  32.                 ) else if "%%e" equ " stat=" (
  33.                         set #"%%f"=%%b
  34.                 ) else if "%%a" equ "  </item>" (
  35.                         for /f "tokens=2 delims=#=" %%x in ('set #') do (
  36.                                 if "%%x" equ "," (
  37.                                         set str=!str!,
  38.                                 ) else (
  39.                                         set str=!str!,"%%x"
  40.                                 )
  41.                         )
  42.                         echo=!str!
  43.                         endlocal
  44.                 )
  45.         ))>>out.csv
  46. )
  47. pause
复制代码
发表于 2024-2-26 14:10:33 | 显示全部楼层
本帖最后由 aloha20200628 于 2024-2-26 14:13 编辑


延续前帖(http://www.bathome.net/thread-68463-1-1.html)的算法逻辑,先给一个处理单个源文件的纯P版(命令行参数指定单个源文件的路径文件名),供楼主随机测试那一堆不同源文件...
楼主的源文件是utf-8+编码,故本脚本运行结果是生成utf-8编码的*.new文件

  1. @echo off &setlocal enabledelayedexpansion
  2. if "%~1"=="" exit/b
  3. chcp 65001>nul
  4. set "tLine=id        type        name"
  5. (for /f tokens^=1-6^ delims^=^"^= %%1 in (' findstr "=" "%~1" ') do for /f "tokens=1-2 delims=        < " %%a in ("%%~1") do (
  6.         if /i "%%~b"=="id" (
  7.                 if defined vLine (echo,!vLine:~1!&set "vLine=")
  8.                 set "vLine=!vLine!        %%2        %%4        %%6"
  9.         ) else if /i "%%~b"=="name" (
  10.                 if not defined _%%2 (set "tLine=!tLine!        %%2" &set "_%%2=1")
  11.                 set "vLine=!vLine!        %%4"
  12.         ) else if /i "%%~b"=="order" (
  13.                 if not defined _%%4 (set "tLine=!tLine!        %%4" &set "_%%4=1")
  14.                 set "vLine=!vLine!        %%6"
  15.         ) else if /i "%%~b"=="val" (
  16.                 if not defined _%%6 (set "tLine=!tLine!        %%6" &set "_%%6=1")
  17.                 set "vLine=!vLine!        %%2"
  18.         )
  19. ))>"%~1.v"
  20. if defined vLine (echo,!vLine:~1!)>>"%~1.v"
  21. echo,!tLine!>"%~1.new" & type "%~1.v">>"%~1.new" & del "%~1.v"
  22. endlocal&exit/b
复制代码
发表于 2024-2-26 14:43:34 | 显示全部楼层
回复 1# zhengwei007

如12楼脚本代码(假设存为 test.bat)用随机性测试均予通过,可用以下一行代码(直接复制到命令行运行即可)完成指定目录中的所有*.xml源文件处理...

  1. for %a in (*.xml) do @test.bat "%~a"
复制代码
 楼主| 发表于 2024-2-27 09:06:53 | 显示全部楼层
谢谢楼上各位,问题已经完美解决。
发表于 2024-2-27 09:15:13 | 显示全部楼层
回复 14# zhengwei007


讨论一下么
各方案的实际执行的优缺点
有讨论才有动力
您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|小黑屋|批处理之家 ( 渝ICP备10000708号 )

GMT+8, 2026-3-18 05:45 , Processed in 0.019336 second(s), 8 queries , File On.

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表