标题: [文本处理] 求助批处理从一堆文本文件中提取关键词写到csv中 [打印本页]
作者: zhengwei007 时间: 2023-12-14 09:58 标题: 求助批处理从一堆文本文件中提取关键词写到csv中
本帖最后由 zhengwei007 于 2023-12-14 10:45 编辑
我想从100多个文档里面,发现有Soul Crystal字符时,截取下面一行的ID 4645,和最后一行的4682,单独存放在csv文件里。
文档中是以<item>开头,</item>结尾的,谢谢大家。
由于不能上传附件,我粘点里面内容吧。- <item>
- <!-- Stormbringer -->
- <ingredient count="1" id="72" />
- <!-- Red Soul Crystal - Stage 5 -->
- <ingredient count="1" id="4634" />
- <!-- Gemstone C -->
- <ingredient count="97" id="2131" />
- <!-- Adena -->
- <ingredient count="291000" id="57" />
- <!-- Stormbringer - Critical Anger -->
- <production count="1" id="4681" />
- </item>
- <item>
- <!-- Stormbringer -->
- <ingredient count="1" id="72" />
- <!-- Green Soul Crystal - Stage 5 -->
- <ingredient count="1" id="4645" />
- <!-- Gemstone C -->
- <ingredient count="97" id="2131" />
- <!-- Adena -->
- <ingredient count="291000" id="57" />
- <!-- Stormbringer - Focus -->
- <production count="1" id="4682" />
- </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,写的丑了点- 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)
楼主提供的样本已测试通过。
- @echo off &setlocal enabledelayedexpansion
- findstr /inc:"Soul Crystal" /inc:"</item>" "test.xml" 2>nul>tmp.0
- (for /f "tokens=1 delims=:" %%k in (tmp.0) do (
- if not defined v1 (call :getV "test.xml" %%k v1) else (
- set/a "n=%%k-2"
- (call :getV "test.xml" !n! v2)
- echo,!v1!,!v2!
- set "v1="
- )
- ))>"test.csv"
- del /q tmp.0
- endlocal &pause &exit/b
- :getV //%1=文件名 %2=行号 %3=返回值变量名
- for /f "usebackq skip=%~2 delims=" %%s in ("%~1") do (
- for /f tokens^=1-4^delims^=^" %%1 in ("%%~s") do (set "%~3=%%4")
- exit/b
- ) & exit/b
复制代码
作者: zhengwei007 时间: 2023-12-14 15:37
谢谢6楼和10楼的兄弟,问题已经全部解决。
作者: 77七 时间: 2023-12-14 16:45
- @echo off
- cd /d "%~dp0"
- (for %%i in (*.xml) do (
- setlocal
- for /f "useback delims=" %%a in ("%%i") do (
- set str=%%a
- setlocal enabledelayedexpansion
- set "str1=!str:Soul Crystal=!"
- set "str2=!str: </item>=!"
- if "!str!" neq "!str1!" (
- endlocal
- set m=1
- ) else if defined m (
- endlocal
- for /f tokens^=4delims^=^" %%x in ("%%a") do (
- set n=%%x
- )
- set m=
- ) else if "!str!" neq "!str2!" (
- endlocal
- if defined n (
- setlocal enabledelayedexpansion
- for /f tokens^=4delims^=^" %%x in ("!_str!") do (
- echo !n!,%%x
- )
- endlocal
- set n=
- )
- ) else (
- endlocal
- )
- set _str=%%a
- )
- endlocal
- ))>data.csv
- pause
复制代码
作者: hfxiang 时间: 2023-12-14 19:17
回复 1# zhengwei007
假设所有xml文件均在同1个文件夹下,用第3方工具gaw( http://bcn.bathome.net/tool/5.1.0/gawk.exe ),在命令行方式下,其实现方法如下:- 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 编辑
- @if(0)==(0) echo off
- dir /b *.xml | cscript -nologo -e:jscript "%~f0" > result.csv
- pause & exit
- @end
-
- var fso = new ActiveXObject('Scripting.FileSystemObject');
-
- while(!WSH.StdIn.AtEndOfStream) {
- var f = WSH.StdIn.ReadLine();
- var s = fso.OpenTextfile(f, 1).ReadAll();
- var m = s.match(/<item>(?:(?!<\/?item>)[\s\S])+<\/item>/g);
- for(var i=0; i<m.length; i++) {
- var m1 = m[i].match(/\bSoul Crystal\b.+\n(?:(?!\bid=).)+\bid="([^"]+)"/);
- var m2 = m[i].match(/\bproduction\b(?:(?!\bid=).)+\bid="([^"]+)"/);
- if(m1 && m2) WSH.Echo(m1[1] + ',' + m2[1]);
- }
- }
复制代码
- @if(0)==(0) echo off
- dir /b *.xml | cscript -nologo -e:jscript "%~f0" > result.csv
- pause & exit
- @end
-
- var xml = new ActiveXObject('Microsoft.XMLDOM');
- var reg = /\bSoul Crystal\b/;
-
- while(!WSH.StdIn.AtEndOfStream) {
- var f = WSH.StdIn.ReadLine();
- getXmlData(f);
- }
-
- function getXmlData(fileName) {
- xml.load(fileName);
- var nodes = xml.selectNodes('//item');
- for(var i=0; i<nodes.length; i++) {
- var s2 = nodes[i].lastChild.getAttribute('id');
- var childs = nodes[i].childNodes;
- for(var j=0; j<childs.length; j++) {
- if(childs[j].nodeName == '#comment' && reg.test(childs[j].text)) {
- var s1 = childs[j+1].getAttribute('id');
- WSH.Echo(s1 + ',' + s2);
- break;
- }
- }
- }
- }
复制代码
作者: Five66 时间: 2023-12-15 02:00
这样行不?- @echo off&chcp 936
- echo 进行中,请耐心等待
- set "outfile=___output.csv"
-
- cd.>"%outfile%"
- for %%b in ("*.xml") do (
- setlocal
- echo,file,%%~b>>%outfile%
- (for /f "skip=1 delims=" %%c in ('findstr /n .* "%%~b"') do (
- set line1=
- set /p line1=
- set line2=%%c
-
- if not defined item (
- setlocal enabledelayedexpansion
- if "!line1:<item>=!" neq "!line1!" (
- for %%- in (1) do endlocal&set item=%%-) else endlocal
- ) else (
-
- setlocal enabledelayedexpansion
- if "!line1:Soul Crystal=!" neq "!line1!" (
- set line3=!line2:* =!&set line3=!line3:~0,-2!
- 2>nul set /a !line3:id=,id!
- for %%- in ("!id!") do endlocal&set o=%%~-&set match=1
- if "!p!" == "!q!" endlocal
- ) else endlocal
-
- if defined match (
- setlocal enabledelayedexpansion
- if "!line2:</item>=!" neq "!line2!" (
- set line3=!line1:* =!&set line3=!line3:~0,-2!
- 2>nul set /a !line3:id=,id!
- echo,!o!,!id!
- endlocal&set o=&set match=&set item=
- ) else endlocal
- )
-
- )
- ))<"%%~b">>"%outfile%"
- endlocal
- )
- echo,&echo 完成&pause
复制代码
作者: WHY 时间: 2023-12-15 20:37
Test.ps1- $out = [Collections.ArrayList]@();
- $comments = Select-XML *.xml -XPath '//item/comment()[contains(string(),"Soul Crystal")]'; #item节点中包含关键字的注释节点
-
- forEach ($comment In $comments) {
- $s1 = $comment.Node.NextSibling.NextSibling.id;
- $s2 = $comment.Node.ParentNode.production.id;
- if ($s1 -ne $null -and $s2 -ne $null) {
- [void]$out.Add($s1 + ',' + $s2);
- }
- }
-
- sc 1.csv -Value $out;
复制代码
作者: qixiaobin0715 时间: 2023-12-21 10:22
本帖最后由 qixiaobin0715 于 2023-12-21 10:36 编辑
第一个for循环主要是排除不含Soul Crystal的xml文件。
变量延迟加在合适的位置即可:- @echo off
- (for /f "delims=" %%i in ('findstr /m /c:"Soul Crystal" *.xml') do (
- for /f "tokens=1,3,4" %%a in ('type "%%i"') do (
- if "%%a"=="<item>" (
- set x=true
- ) else if "%%a"=="</item>" (
- set x=
- setlocal enabledelayedexpansion
- for /f "tokens=2 delims==" %%d in ("!str1!") do echo,!str2!,%%~d
- endlocal
- ) else if defined x (
- if "%%b%%c"=="SoulCrystal" (
- set y=true
- ) else if defined y (
- set y=
- for /f "tokens=2 delims==" %%d in ("%%b") do set str2=%%~d
- )
- set str1=%%b
- )
- )
- ))>out.csv
- pause
复制代码
作者: qixiaobin0715 时间: 2023-12-22 16:12
受10楼代码启示,这样应当在逻辑上更容易理解些:
1.找出"Soul Crystal"和"</item>"所在的行数;
2.根据第1条找出数据所在行的行数,并随后对这些行进行处理,得到所需ID数值。- @echo off
- (for /f "delims=" %%i in ('findstr /m /c:"Soul Crystal" *.xml') do (
- setlocal enabledelayedexpansion
- for /f "tokens=1,2 delims=: " %%j in ('findstr /ilnc:"Soul Crystal" /inc:"</item>" "%%i"') do (
- set n=%%j
- if "%%k"=="</item>" (
- set /a n-=1
- set _!n!=true
- ) else (
- set /a n+=1
- set #!n!=true
- )
- )
- for /f "tokens=1,4 delims=: " %%a in ('findstr /n .* "%%i"') do (
- if defined #%%a (
- for /f "tokens=2 delims==" %%c in ("%%b") do set "str=%%~c"
- ) else if defined _%%a (
- for /f "tokens=2 delims==" %%c in ("%%b") do echo,!str!,%%~c
- )
- )
- endlocal
- ))>out.csv
- 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 循环中处理。- @echo off
- set "XPath1=//item/comment()[contains(string(),'Soul Crystal')]/following-sibling::*[1]"
- set "XPath2=//item/comment()[contains(string(),'Soul Crystal')]/following-sibling::*[last()]"
- setlocal enabledelayedexpansion
- (for %%i in (*.xml) do (
- for /f %%j in ('xml sel -t -m "%XPath1%|%XPath2%" -n -v "@id" "%%i"') do (
- if defined s (
- echo;!s!,%%j
- set "s="
- ) else (
- set "s=%%j"
- )
- )
- )) > 0.csv
- pause
复制代码
sed下载:http://bcn.bathome.net/tool/4.8/sed.exe
原理大概是:
先定位 <item> 与 </item> 区间,再定位 Soul Crystal 与 production 区间,
找到关键字Soul Crystal,把下一行hold住;找到production的行,hold追加到模式空间,再回显。- 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 |