Board logo

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

作者: zhengwei007    时间: 2024-2-25 18:38     标题: 【已解决】求助批处理从一堆文本文件中提取关键词写到csv中

本帖最后由 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的分享
作者: czjt1234    时间: 2024-2-26 08:59

本帖最后由 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
复制代码

作者: zhengwei007    时间: 2024-2-26 10:19

本帖最后由 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=”就好了。
作者: czjt1234    时间: 2024-2-26 10:26

<add 这行算不算?
作者: likeyou32    时间: 2024-2-26 10:39

回复 2# czjt1234


    您这是批处理吗? 好像是vba吧, ,而且这oFSO.GetFolder(PATH).Files 好像连vba都不是
作者: ShowCode    时间: 2024-2-26 10:55

回复 5# likeyou32


是用BAT调用的VBS
http://bbs.bathome.net/thread-4610-1-1.html
作者: zhengwei007    时间: 2024-2-26 10:59

回复 4# czjt1234

都算,只是不要前面的order,你就把代码看成 <add stat="accCombat" val="4.75" />,字段是accCombat,值是4.75
作者: 77七    时间: 2024-2-26 12:17

  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" />
复制代码

最后两行也算吗?
作者: zhengwei007    时间: 2024-2-26 12:45

都算,stat的值就是列表标题,val就是值。
作者: czjt1234    时间: 2024-2-26 13:26

  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
复制代码

作者: 77七    时间: 2024-2-26 13:58

  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
复制代码

作者: aloha20200628    时间: 2024-2-26 14:10

本帖最后由 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
复制代码

作者: aloha20200628    时间: 2024-2-26 14:43

回复 1# zhengwei007

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

作者: zhengwei007    时间: 2024-2-27 09:06

谢谢楼上各位,问题已经完美解决。
作者: czjt1234    时间: 2024-2-27 09:15

回复 14# zhengwei007


讨论一下么
各方案的实际执行的优缺点
有讨论才有动力
作者: zhengwei007    时间: 2024-2-27 23:06

回复  zhengwei007


讨论一下么
各方案的实际执行的优缺点
有讨论才有动力
czjt1234 发表于 2024-2-27 09:15


从结果看,你们的代码效果都能完美实现我想要的功能,运行速度都挺快的,大概5秒就出结果了,优点很明显。要让我这个外行说,我总结一下:
10楼代码:
        1)默认情况下,我必须将bat另存为ANSI 编码,因为我这WIN11默认是UTF-8。
        2)脚本里面需要手动指定两个路径,我分别重新指定过了。
11楼代码:
我认为没什么说的,我将代码在当前目录保存好后就可以直接运行了。

所以从上面看,11楼代码是最傻瓜式的。




欢迎光临 批处理之家 (http://bbs.bathome.net/) Powered by Discuz! 7.2