Board logo

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

作者: zhengwei007    时间: 2023-12-14 09:58     标题: 求助批处理从一堆文本文件中提取关键词写到csv中

本帖最后由 zhengwei007 于 2023-12-14 10:45 编辑

我想从100多个文档里面,发现有Soul Crystal字符时,截取下面一行的ID 4645,和最后一行的4682,单独存放在csv文件里。
文档中是以<item>开头,</item>结尾的,谢谢大家。
由于不能上传附件,我粘点里面内容吧。
  1. <item>
  2. <!-- Stormbringer -->
  3. <ingredient count="1" id="72" />
  4. <!-- Red Soul Crystal - Stage 5 -->
  5. <ingredient count="1" id="4634" />
  6. <!-- Gemstone C -->
  7. <ingredient count="97" id="2131" />
  8. <!-- Adena -->
  9. <ingredient count="291000" id="57" />
  10. <!-- Stormbringer - Critical Anger -->
  11. <production count="1" id="4681" />
  12. </item>
  13. <item>
  14. <!-- Stormbringer -->
  15. <ingredient count="1" id="72" />
  16. <!-- Green Soul Crystal - Stage 5 -->
  17. <ingredient count="1" id="4645" />
  18. <!-- Gemstone C -->
  19. <ingredient count="97" id="2131" />
  20. <!-- Adena -->
  21. <ingredient count="291000" id="57" />
  22. <!-- Stormbringer - Focus -->
  23. <production count="1" id="4682" />
  24. </item>
复制代码
从这里提取4634和4681即可,每个文件里可能有多个这样的内容结构。
最终csv就是这样:
4634,4681
4645,4682

链接:https://pan.baidu.com/s/13ecRnqY4tPRaoFcVBEBLTg
提取码:xlit
这里存放了几个真实的文本文件的下载地址。
作者: Batcher    时间: 2023-12-14 10:05

回复 1# zhengwei007


    请选择其中3个文件打包压缩上传到网盘我试试
作者: zhengwei007    时间: 2023-12-14 10:30

链接:https://pan.baidu.com/s/13ecRnqY4tPRaoFcVBEBLTg
提取码:xlit
--来自百度网盘超级会员V9的分享

谢谢管理。
作者: Batcher    时间: 2023-12-14 10:37

回复 3# zhengwei007


    请编辑一下顶楼的帖子,把下载链接放进去,方便他人看到。
作者: zhengwei007    时间: 2023-12-14 10:46

回复  zhengwei007


    请编辑一下顶楼的帖子,把下载链接放进去,方便他人看到。
Batcher 发表于 2023-12-14 10:37



   
好的,已经编辑完成。
作者: wanghan519    时间: 2023-12-14 12:52

用的busybox的sh,这东西可以打包成exe,写的丑了点
  1. for f in *.xml; do awk -v RS='</item>' -F '\n' '/Soul Crystal/{for(i=1;i<=NF;i++){if($i~/Soul Crystal/){gsub(".*id=\"|\".*","",$(i+1));gsub(".*id=\"|\".*","",$(NF-1));print $(i+1)","$(NF-1)}}}' "$f" > "$f.csv"; done
复制代码

作者: zhengwei007    时间: 2023-12-14 13:24

用的busybox的sh,这东西可以打包成exe,写的丑了点
wanghan519 发表于 2023-12-14 12:52



可以做成批处理文件吗?.bat后缀,我可以直接执行的那种。我这没有linux,谢谢!
作者: wanghan519    时间: 2023-12-14 14:07

回复 7# zhengwei007


    呃,bat处理引号我是真不会。。。
可以下个busybox-w32执行,也就0.5M,提供sh环境包括awk,且可以把脚本编译成exe,很方便的小工具
作者: zhengwei007    时间: 2023-12-14 14:55

回复  zhengwei007


    呃,bat处理引号我是真不会。。。
可以下个busybox-w32执行,也就0.5M,提供 ...
wanghan519 发表于 2023-12-14 14:07



你好,我试过了,可能有一点没说清楚,是所有数据全部汇总到一个csv下,不是单独的csv文件。随便起个名字,data.csv就行。
作者: aloha20200628    时间: 2023-12-14 15:08


测试文件名假设为 test.xml
获取结果文件名为 test.csv
如下代码存为批处理脚本文件(test.cmd 或 test.bat)
楼主提供的样本已测试通过。
  1. @echo off &setlocal enabledelayedexpansion
  2. findstr /inc:"Soul Crystal" /inc:"</item>" "test.xml" 2>nul>tmp.0
  3. (for /f "tokens=1 delims=:" %%k in (tmp.0) do (
  4. if not defined v1 (call :getV "test.xml" %%k v1) else (
  5. set/a "n=%%k-2"
  6. (call :getV "test.xml" !n! v2)
  7. echo,!v1!,!v2!
  8. set "v1="
  9. )
  10. ))>"test.csv"
  11. del /q tmp.0
  12. endlocal &pause &exit/b
  13. :getV //%1=文件名 %2=行号 %3=返回值变量名
  14. for /f "usebackq skip=%~2 delims=" %%s in ("%~1") do (
  15. for /f tokens^=1-4^delims^=^" %%1 in ("%%~s") do (set "%~3=%%4")
  16. exit/b
  17. ) & exit/b
复制代码

作者: zhengwei007    时间: 2023-12-14 15:37

谢谢6楼和10楼的兄弟,问题已经全部解决。
作者: 77七    时间: 2023-12-14 16:45

  1. @echo off
  2. cd /d "%~dp0"
  3. (for %%i in (*.xml) do (
  4. setlocal
  5. for /f "useback delims=" %%a in ("%%i") do (
  6. set str=%%a
  7. setlocal enabledelayedexpansion
  8. set "str1=!str:Soul Crystal=!"
  9. set "str2=!str: </item>=!"
  10. if "!str!" neq "!str1!" (
  11. endlocal
  12. set m=1
  13. ) else if defined m (
  14. endlocal
  15. for /f tokens^=4delims^=^" %%x in ("%%a") do (
  16. set n=%%x
  17. )
  18. set m=
  19. ) else if "!str!" neq "!str2!" (
  20. endlocal
  21. if defined n (
  22. setlocal enabledelayedexpansion
  23. for /f tokens^=4delims^=^" %%x in ("!_str!") do (
  24. echo !n!,%%x
  25. )
  26. endlocal
  27. set n=
  28. )
  29. ) else (
  30. endlocal
  31. )
  32. set _str=%%a
  33. )
  34. endlocal
  35. ))>data.csv
  36. pause
复制代码

作者: hfxiang    时间: 2023-12-14 19:17

回复 1# zhengwei007

假设所有xml文件均在同1个文件夹下,用第3方工具gaw( http://bcn.bathome.net/tool/5.1.0/gawk.exe ),在命令行方式下,其实现方法如下:
  1. awk -v"OFS=," "/^\t+<item>$/,/^\t+<\/item>$/{if(/Soul Crystal/)exist_id=1;if(/^\t+<ingredient count=\"1\" id=\"[0-9]+\" \/>$/)if(exist_id)A=gensub(/^\t+<ingredient count=\"1\" id=\"([0-9]+)\" \/>$/,\"\\1\",\"g\",$0);if(/^\t+<production count=\"1\" id=\"[0-9]+\" \/>$/)if(exist_id)print A,gensub(/^\t+<production count=\"1\" id=\"([0-9]+)\" \/>$/,\"\\1\",\"g\",$0);if(/^\t+<\/item>$/)exist_id=0}" *.xml>out.csv
复制代码

作者: WHY    时间: 2023-12-14 20:39

本帖最后由 WHY 于 2023-12-17 23:02 编辑
  1. @if(0)==(0) echo off
  2. dir /b *.xml | cscript -nologo -e:jscript "%~f0" > result.csv
  3. pause & exit
  4. @end
  5. var fso = new ActiveXObject('Scripting.FileSystemObject');
  6. while(!WSH.StdIn.AtEndOfStream) {
  7.     var f = WSH.StdIn.ReadLine();
  8.     var s = fso.OpenTextfile(f, 1).ReadAll();
  9.     var m = s.match(/<item>(?:(?!<\/?item>)[\s\S])+<\/item>/g);
  10.     for(var i=0; i<m.length; i++) {
  11.         var m1 = m[i].match(/\bSoul Crystal\b.+\n(?:(?!\bid=).)+\bid="([^"]+)"/);
  12.         var m2 = m[i].match(/\bproduction\b(?:(?!\bid=).)+\bid="([^"]+)"/);
  13.         if(m1 && m2) WSH.Echo(m1[1] + ',' + m2[1]);
  14.     }
  15. }
复制代码
  1. @if(0)==(0) echo off
  2. dir /b *.xml | cscript -nologo -e:jscript "%~f0" > result.csv
  3. pause & exit
  4. @end
  5. var xml = new ActiveXObject('Microsoft.XMLDOM');
  6. var reg = /\bSoul Crystal\b/;
  7. while(!WSH.StdIn.AtEndOfStream) {
  8.     var f = WSH.StdIn.ReadLine();
  9.     getXmlData(f);
  10. }
  11. function getXmlData(fileName) {
  12.     xml.load(fileName);
  13.     var nodes = xml.selectNodes('//item');
  14.     for(var i=0; i<nodes.length; i++) {
  15.         var s2 = nodes[i].lastChild.getAttribute('id');
  16.         var childs = nodes[i].childNodes;
  17.         for(var j=0; j<childs.length; j++) {
  18.             if(childs[j].nodeName == '#comment' && reg.test(childs[j].text)) {
  19.                 var s1 = childs[j+1].getAttribute('id');
  20.                 WSH.Echo(s1 + ',' + s2);
  21.                 break;
  22.             }
  23.         }
  24.     }
  25. }
复制代码

作者: Five66    时间: 2023-12-15 02:00

这样行不?
  1. @echo off&chcp 936
  2. echo 进行中,请耐心等待
  3. set "outfile=___output.csv"
  4. cd.>"%outfile%"
  5. for %%b in ("*.xml") do (
  6. setlocal
  7. echo,file,%%~b>>%outfile%
  8. (for /f "skip=1 delims=" %%c in ('findstr /n .* "%%~b"') do (
  9. set line1=
  10. set /p line1=
  11. set line2=%%c
  12. if not defined item (
  13. setlocal enabledelayedexpansion
  14. if "!line1:<item>=!" neq "!line1!" (
  15. for %%- in (1) do endlocal&set item=%%-) else endlocal
  16. ) else (
  17. setlocal enabledelayedexpansion
  18. if "!line1:Soul Crystal=!" neq "!line1!" (
  19. set line3=!line2:* =!&set line3=!line3:~0,-2!
  20. 2>nul set /a !line3:id=,id!
  21. for %%- in ("!id!") do endlocal&set o=%%~-&set match=1
  22. if "!p!" == "!q!" endlocal
  23. ) else endlocal
  24. if defined match (
  25. setlocal enabledelayedexpansion
  26. if "!line2:</item>=!" neq "!line2!" (
  27. set line3=!line1:* =!&set line3=!line3:~0,-2!
  28. 2>nul set /a !line3:id=,id!
  29. echo,!o!,!id!
  30. endlocal&set o=&set match=&set item=
  31. ) else endlocal
  32. )
  33. )
  34. ))<"%%~b">>"%outfile%"
  35. endlocal
  36. )
  37. echo,&echo 完成&pause
复制代码

作者: WHY    时间: 2023-12-15 20:37

Test.ps1
  1. $out = [Collections.ArrayList]@();
  2. $comments = Select-XML *.xml -XPath '//item/comment()[contains(string(),"Soul Crystal")]'; #item节点中包含关键字的注释节点
  3. forEach ($comment In $comments) {
  4.     $s1 = $comment.Node.NextSibling.NextSibling.id;
  5.     $s2 = $comment.Node.ParentNode.production.id;
  6.     if ($s1 -ne $null -and $s2 -ne $null) {
  7.         [void]$out.Add($s1 + ',' + $s2);
  8.     }
  9. }
  10. sc 1.csv -Value $out;
复制代码

作者: qixiaobin0715    时间: 2023-12-21 10:22

本帖最后由 qixiaobin0715 于 2023-12-21 10:36 编辑

第一个for循环主要是排除不含Soul Crystal的xml文件。
变量延迟加在合适的位置即可:
  1. @echo off
  2. (for /f "delims=" %%i in ('findstr /m /c:"Soul Crystal" *.xml') do (
  3.     for /f "tokens=1,3,4" %%a in ('type "%%i"') do (
  4.         if "%%a"=="<item>" (
  5.             set x=true
  6.         ) else if "%%a"=="</item>" (
  7.             set x=
  8.             setlocal enabledelayedexpansion
  9.             for /f "tokens=2 delims==" %%d in ("!str1!") do echo,!str2!,%%~d
  10.             endlocal
  11.         ) else if defined x (
  12.             if "%%b%%c"=="SoulCrystal" (
  13.                 set y=true
  14.             ) else if defined y (
  15.                 set y=
  16.                 for /f "tokens=2 delims==" %%d in ("%%b") do set str2=%%~d
  17.             )
  18.             set str1=%%b
  19.         )
  20.     )
  21. ))>out.csv
  22. pause
复制代码

作者: qixiaobin0715    时间: 2023-12-22 16:12

受10楼代码启示,这样应当在逻辑上更容易理解些:
1.找出"Soul Crystal"和"</item>"所在的行数;
2.根据第1条找出数据所在行的行数,并随后对这些行进行处理,得到所需ID数值。
  1. @echo off
  2. (for /f "delims=" %%i in ('findstr /m /c:"Soul Crystal" *.xml') do (
  3.     setlocal enabledelayedexpansion
  4.     for /f "tokens=1,2 delims=: " %%j in ('findstr /ilnc:"Soul Crystal" /inc:"</item>" "%%i"') do (
  5.         set n=%%j
  6.         if "%%k"=="</item>" (
  7.             set /a n-=1
  8.             set _!n!=true
  9.         ) else (
  10.             set /a n+=1
  11.             set #!n!=true
  12.         )
  13.     )
  14.     for /f "tokens=1,4 delims=: " %%a in ('findstr /n .* "%%i"') do (
  15.         if defined #%%a (
  16.             for /f "tokens=2 delims==" %%c in ("%%b") do set "str=%%~c"
  17.         ) else if defined _%%a (
  18.             for /f "tokens=2 delims==" %%c in ("%%b") do echo,!str!,%%~c
  19.         )
  20.     )
  21.     endlocal
  22. ))>out.csv
  23. pause
复制代码

作者: yyz219    时间: 2023-12-22 21:48

回复 1# zhengwei007

啊哦,来晚了,该分享文件已过期
作者: WHY    时间: 2023-12-25 14:28

第3方 xmlStarLet 下载:http://bcn.bathome.net/tool/xml.exe
找到包含 Soul Crystal 的注释节点后面的下一个节点XPath1以及最后一个节点XPath2,放到 for 循环中处理。
  1. @echo off
  2. set "XPath1=//item/comment()[contains(string(),'Soul Crystal')]/following-sibling::*[1]"
  3. set "XPath2=//item/comment()[contains(string(),'Soul Crystal')]/following-sibling::*[last()]"
  4. setlocal enabledelayedexpansion
  5. (for %%i in (*.xml) do (
  6.     for /f %%j in ('xml sel -t -m "%XPath1%|%XPath2%" -n -v "@id" "%%i"') do (
  7.         if defined s (
  8.             echo;!s!,%%j
  9.             set "s="
  10.         ) else (
  11.             set "s=%%j"
  12.         )
  13.     )
  14. )) > 0.csv
  15. pause
复制代码
sed下载:http://bcn.bathome.net/tool/4.8/sed.exe
原理大概是:
先定位 <item> 与 </item> 区间,再定位 Soul Crystal 与 production 区间,
找到关键字Soul Crystal,把下一行hold住;找到production的行,hold追加到模式空间,再回显。
  1. sed -r -n "/<item>/,/<\/item>/{/Soul Crystal/,/production/{/Soul Crystal/{n;h};/production/{G;s/^.*id=\"([0-9]+)\".*\n.*id=\"([0-9]+)\".*$/\2,\1/;p}}}" *.xml > 1.csv
复制代码





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