[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖

[文本处理] 求批处理把一个带分隔符的长字符串拆成一行行的

本帖最后由 zhengwei007 于 2024-1-5 15:12 编辑

我有个csv文件,里面有很多类似的样式如下,我随意粘了3行,请大家帮忙看看,可以直接粘到csv里。
  1. 1 adena 7 10 100 70 apprentice's_shoes 1 1 63.7931 cloth_shoes 1 1 12.069 leather_sandals 1 1 12.069 short_gloves 1 1 12.0689 10.9692 stem 1 1 75 suede 1 1 25 1.3062
  2. 3 adena 25 35 100 70 apprentice's_earing 1 1 30.9859 magic_ring 1 1 46.0094 necklace_of_magic 1 1 23.0047 15.1467 varnish 1 1 11.3636 coal 1 1 11.3636 charcoal 1 1 11.3636 rp_bow 1 1 9.0909 wooden_arrow 20 39 56.8183 6.0713
  3. 4 adena 34 48 100 70 short_leather_gloves 1 1 33.3333 cotton_shoes 1 1 33.3333 crude_leather_shoes 1 1 33.3334 2.4971 stem 1 1 75 suede 1 1 25 2.5262
复制代码
如果英文名称后面是4组数字,则将数字直接写在后面,然后另起一行。
如果英文名称后面是3组数字,则将将后面出现4组数字的最后一组,写到前面的最后一组给补齐即可。
所以根据上面的内容,我希望通过批处理操作后,自动调整成以下格式:
  1. 1 adena 7 10 100 70
  2. 1 apprentice's_shoes 1 1 63.7931 10.9692
  3. 1 cloth_shoes 1 1 12.069 10.9692
  4. 1 leather_sandals 1 1 12.069 10.9692
  5. 1 short_gloves 1 1 12.0689 10.9692
  6. 1 stem 1 1 75 1.3062
  7. 1 suede 1 1 25 1.3062
  8. 3 adena 25 35 100 70
  9. 3 apprentice's_earing 1 1 30.9859 15.1467
  10. 3 magic_ring 1 1 46.0094 15.1467
  11. 3 necklace_of_magic 1 1 23.0047 15.1467
  12. 3 varnish 1 1 11.3636 6.0713
  13. 3 coal 1 1 11.3636 6.0713
  14. 3 charcoal 1 1 11.3636 6.0713
  15. 3 rp_bow 1 1 9.0909 6.0713
  16. 3 wooden_arrow 1 1 56.8183 6.0713
  17. 4 adena 34 48 100 70
  18. 4 short_leather_gloves 1 1 33.3333 2.4971
  19. 4 cotton_shoes 1 1 33.3333 2.4971
  20. 4 crude_leather_shoes 1 1 33.3334 2.4971
  21. 4 stem 1 1 75 2.5262
  22. 4 suede 1 1 25 2.5262
复制代码
这个是我把json格式的多余字符全删除了,这玩意原本是json。。。谢谢各位大佬。

#10 的powershell 很合适啊

TOP

回复 1# zhengwei007
此类在俺看来属于数据格式化一类的问题,建议用第3方工具gawk(http://bcn.bathome.net/tool/4.1.0/gawk.exe)处置,其在命令行下实现指令如下:
  1. gawk "{n=patsplit($0,a,/[a-zA-Z][^\t]+(\t[0-9.]+){3,4}/);for(i=n;i>0;i--)if(a[i]~/[a-zA-Z][^\t]+(\t[0-9.]+){4}/){a4=gensub(/^.+\t([^\t]+)$/,\"\\1\",\"g\",a[i])}else{a[i]=a[i] \"\t\" a4};for(i=1;i<=n;i++)print $1\"\t\"a[i]}" a.csv>b.txt
复制代码

TOP

修改14楼的代码,以便解决15楼的问题:
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. (for /f "tokens=1*" %%a in (a.csv) do (
  4.     setlocal enabledelayedexpansion
  5.     set Line="%%b"
  6.     set Line=!Line: =" "!
  7.     set Line=!Line:""=!
  8.     for %%j in (!line!,x) do (
  9.         for /f "delims=0123456789." %%k in ("#%%~j") do (
  10.             if not "%%k"=="#" (
  11.                 if !x! equ 3 (
  12.                     set /a y+=1
  13.                     set _!y!=!str!
  14.                 ) else if !x! equ 4 (
  15.                     if defined _!y! (
  16.                         for /l %%l in (1,1,!y!) do (
  17.                             if defined FourthCol (
  18.                                 echo,%%a !_%%l! !FourthCol!
  19.                             ) else (
  20.                                 echo,%%a !_%%l!
  21.                             )
  22.                             set _%%l=
  23.                         )
  24.                         set FourthCol=
  25.                         set y=0
  26.                     )
  27.                     echo,%%a !str!
  28.                 )
  29.                 set str=%%~j
  30.                 set x=0
  31.             ) else (
  32.                 set str=!str! %%~j
  33.                 set /a x+=1
  34.                 if !x! equ 4 set FourthCol=%%~j
  35.             )
  36.         )
  37.     )
  38.     endlocal
  39. ))>out.csv
  40. pause
复制代码
这种问题对于锻炼逻辑思维很有好处。顺便练习一下if及set命令的用法。

TOP

本帖最后由 qixiaobin0715 于 2024-1-12 16:32 编辑

13、14楼提供代码好像不行,刚发现楼主提供的csv文件在599行中,英文名称含有空格,分割时会出现问题。以上代码作废。
使用不带参数的for循环,按水平制表符分割字符串时不能存在干扰字符,即要分割的字符串中不能存在空格、逗号、分号、等号等这类字符,这种情况应当也能解决,不过可能要在前面多几行代码处理一下字符串即可。

TOP

本帖最后由 qixiaobin0715 于 2024-1-12 11:20 编辑

主要是练练手。
将楼上代码修改如下:
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. (for /f "tokens=1*" %%a in (a.csv) do (
  4.     setlocal enabledelayedexpansion
  5.     for %%j in (%%b,x) do (
  6.         for /f "delims=0123456789." %%k in ("#%%j") do (
  7.             if not "%%k"=="#" (
  8.                 if !x! equ 3 (
  9.                     set /a y+=1
  10.                     set _!y!=!str!
  11.                 ) else if !x! equ 4 (
  12.                     if defined _!y! (
  13.                         for /l %%l in (1,1,!y!) do (
  14.                             if defined FourthCol (
  15.                                 echo,%%a !_%%l! !FourthCol!
  16.                             ) else (
  17.                                 echo,%%a !_%%l!
  18.                             )
  19.                             set _%%l=
  20.                         )
  21.                         set FourthCol=
  22.                         set y=0
  23.                     )
  24.                     echo,%%a !str!
  25.                 )
  26.                 set str=%%j
  27.                 set x=0
  28.             ) else (
  29.                 set str=!str! %%j
  30.                 set /a x+=1
  31.                 if !x! equ 4 set FourthCol=%%j
  32.             )
  33.         )
  34.     )
  35.     endlocal
  36. ))>out.csv
  37. pause
复制代码

TOP

本帖最后由 qixiaobin0715 于 2024-1-12 11:11 编辑

考虑不是太成熟,代码应当还能简化,只是提供一种思路:
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. (for /f "tokens=1*" %%a in (a.csv) do (
  4.     setlocal enabledelayedexpansion
  5.     set FirstCol=%%a
  6.     for %%j in (%%b) do (
  7.         for /f "delims=0123456789." %%k in ("#%%j") do (
  8.             if not "%%k"=="#" (
  9.                 if !x! equ 3 (
  10.                     set /a y+=1
  11.                     set _!y!=!str!
  12.                 ) else if !x! equ 4 (
  13.                     if defined _!y! (
  14.                         for /l %%l in (1,1,!y!) do (
  15.                             if defined FourthCol (
  16.                                 echo,%%a !_%%l! !FourthCol!
  17.                             ) else (
  18.                                 echo,%%a !_%%l!
  19.                             )
  20.                             set _%%l=
  21.                         )
  22.                         set FourthCol=
  23.                         set y=0
  24.                     )
  25.                     echo,%%a !str!
  26.                 )
  27.                 set str=%%j
  28.                 set x=0
  29.             ) else (
  30.                 set str=!str! %%j
  31.                 set /a x+=1
  32.                 if !x! equ 4 set FourthCol=%%j
  33.             )
  34.         )
  35.     )
  36.     if defined _!y! (
  37.         for /l %%l in (1,1,!y!) do (
  38.             if defined FourthCol (
  39.                 echo,!FirstCol! !_%%l! !FourthCol!
  40.             ) else (
  41.                 echo,!FirstCol! !_%%l!
  42.             )
  43.         )
  44.     )
  45.     echo,!FirstCol! !str!
  46.     endlocal
  47. ))>out.csv
  48. pause
复制代码

TOP


用楼主在4楼提供的样本(存为:样本3行.txt)练了一把纯P脑力操,代码如下存为test.bat
先用字符串替换函数把源文收拾利索,再丢给 for/f 分割器逐项扫描.. 幸亏有变量名字典作为遍历回查存储器,使得代码轻量化...
再用7楼提供的样本文件(下载保存为:样本462行.txt)运行结果输出4370行一楼所求格式化数据,行内分割符为制表符
     test.bat "样本3行.txt">"样本3行.new"

     test.bat "样本462行.txt">"样本462行.new"
  1. @echo off
  2. for /f "tokens=1* delims= " %%1 in (%1) do (
  3. setlocal enabledelayedexpansion
  4. set "dn=0" &set "nq=%%1" &set "s=%%2;z" &set "s=!s:*{=!"
  5. for %%c in ( [,],{,} ) do (set "s=!s:%%c=!")
  6. for %%a in (!s!) do (
  7. set "v=%%a" &set "v1=!v:~,1!"
  8. if "!v1!" geq "0" if "!v1!" leq "9" (
  9. for %%k in (!n!) do (set "_%%k=!_%%k! !v!")
  10. set "lastD=!v!" &set/a "dn+=1"
  11. ) else (
  12. if !dn! equ 3 (set "nmax=!nmax! !n!") else if !dn! equ 4 (
  13. if defined nmax for %%k in (!nmax!) do (echo,!_%%k! !lastD!)
  14. for %%k in (!n!) do (echo,!_%%k!)
  15. set "n=0" &set "nmax="
  16. )
  17. set/a "n+=1, dn=0" & set "_!n!=!nq! !v!"
  18. )
  19. )
  20. endlocal
  21. )
  22. exit/b
复制代码

TOP

谢谢大家,已经解决了!

TOP

回复 4# zhengwei007


    用4楼的例子,试一下系统自带的powershell
另存为bat文件运行
  1. #@&cls&powershell "type '%~0'|out-string|iex"&pause&exit
  2. gc test.json|%{
  3. [regex]::Matches($_,'\{(?<k>{\[[^\]]+\][^\}]+\};?)+\};(?<v>[^\}]+)')|%{
  4. $v=$_.groups['v'].value
  5. $_.groups['k'].captures.value|%{$_ -replace '^\{\[([^\]]+)\];([^;]+);([^;]+);([^;]+)\};?',"`$1`t`$2`t`$3`t`$4`t$v"}
  6. }
  7. }
复制代码

TOP

回复 8# zhengwei007
  1. ret = []
  2. with open('a.csv', 'r') as f:
  3.     for i in f:
  4.         arr = i.strip().split('\t')
  5.         a = arr[0]
  6.         b = []
  7.         for j in arr[1:]:
  8.             try:
  9.                 float(j)
  10.                 b.append(j)
  11.             except:
  12.                 if b:
  13.                     ret.append(b)
  14.                 if len(b) == 6:
  15.                     for k in ret:
  16.                         k.append(b[-1])
  17.                 b = [a, j]
  18.         ret.append(b)
  19.         for k in ret:
  20.             k.append(b[-1])
  21. with open('b.csv', 'w') as f:
  22.     f.write('\n'.join(map(lambda x:'\t'.join(x[:6]), ret)))
复制代码

TOP

回复  zhengwei007


    这也不是json啊。。。
没有可用的工具,能想到的就是用perl或者c#里正则的平 ...
wanghan519 发表于 2024-1-5 15:45



   
可以帮我加个写到一个新的文件中吗?我用网上的在线编译,可以使用。但内容过多,复制不完整。请帮我在代码最下面加一个可以生成一个新的文件,将所有结果全部写到b.csv里吧。

TOP

本帖最后由 zhengwei007 于 2024-1-5 16:25 编辑

python我是一点不会,我进入环境了但不会运行~
我把文件发你,可以帮我导一下吗?
链接:https://pan.baidu.com/s/1jiRecvqIOPAw4dwRjOaGFw
提取码:eurj
--来自百度网盘超级会员V9的分享

TOP

那我去试试你上面的PY

TOP

回复 4# zhengwei007


    这也不是json啊。。。
没有可用的工具,能想到的就是用perl或者c#里正则的平衡组,好麻烦
还不如py写的,而且如果改用vb,vb里的数组又不能动态扩展,写起来更麻烦

TOP

返回列表