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

[文本处理] 【已解决】如何使用gawk处理文本四元组的分割与合并

本帖最后由 思想之翼 于 2025-3-9 15:44 编辑

A.txt记录多行数值,格式为:
1234567
8888888
1122339
......

若将A.txt记录的数值,进行四元组分割,可以得到按照位置顺序命名的35个文本:1234.txt 1235.txt 1236.txt 1237.txt 1245.txt 1246.txt 1247.txt 1256.txt 1257.txt 1267.txt 1345.txt 1346.txt 1347.txt 1356.txt 1357.txt 1367.txt 1456.txt 1457.txt 1467.txt 1567.txt 2345.txt 2346.txt 2347.txt 2356.txt 2357.txt 2367.txt 2456.txt 2457.txt 2467.txt 2567.txt 3456.txt 3457.txt 3467.txt 3567.txt 4567.txt

这35个文本,记录对应位置的数据:
1234.txt:
1234
8888
1122

1235.txt:
1235
8888
1123

1236.txt:
1236
8888
1123

1237.txt:
1237
8888
1129
......

4567.txt:
4567
8888
2339

【问题1】如何使用第三方工具gawk,按照位置顺序四元组合,将A.txt分割成35个文本?
【问题2】如何使用第三方工具gawk,将上述35个文本,按照对应的位置顺序,拼接成A.txt?(35个文本行数不同且有重复

突然意识到一个问题
难道生成的文本名字不是根据第一行的组合来命名的???
而是不管第一行是啥都是1234.txt 1235.txt 1236.txt 1237.txt 1245.txt 1246.txt 1247.txt 1256.txt 1257.txt 1267.txt 1345.txt 1346.txt 1347.txt 1356.txt 1357.txt 1367.txt 1456.txt 1457.txt 1467.txt 1567.txt 2345.txt 2346.txt 2347.txt 2356.txt 2357.txt 2367.txt 2456.txt 2457.txt 2467.txt 2567.txt 3456.txt 3457.txt 3467.txt 3567.txt 4567.txt

TOP

回复 2# Five66


        啊 ,2楼的代码结果顺序并不正确 ,除了第一行 ,后面的都偏移了1

改正如下 ,批处理文件中运行(cmd窗口运行的话将双英文百分号给位单英文百分号)
  1. gawk "function fff(a,b,c,d,e){X[x]=c;Y[y]=d;Z[z]=e;for(C[i]=Y[y];C[i]<=a-1;C[i]++){t=Z[z]\"\"B[C[i]+1];if(length(t)==b){if(u){o=m%%n;print t>>D[o]\".txt\";m++}else{D[n++]=t;print t>t\".txt\"}}else{l=C[i]+1;x++;y++;z++;i++;fff(a,b,c,l,t)}};x--;y--;z--;i--;};BEGIN{u=0}{split($0,A,/./,B);fff(7,4,1,0,\"\");u++}" A.txt
复制代码
补上一个问题二 ,仅适用原来文本第一行为1234567并且是7选4的组合 ,合并后文件名为m_A.txt
  1. gawk "ARGIND==1{A[++i]=$0}ARGIND>1{++l;if(l>i){l=1};c=$0;s=substr(c,length(c),1);A[l]=A[l]\"\"s}END{for(k=1;k<=i;k++)print A[k];}" 1234.txt 1235.txt 1236.txt 1237.txt >m_A.txt
复制代码
同问题二 ,原来文本第一行为可为任意 ,并且可是任意选任意的组合(设置变量m跟n) ,因为是通过文件创建时间来决定顺序的 ,结果可能不准确 ,合并后文件名为m_A.txt
  1. dir /tc|sort|gawk -v"m=7" -v"n=4" "{split($0,D,/ +/);s=length(D);if(match(D[s],/txt$/))if(length(D[s])==n+4)F[++i]=D[s]}END{for(i=1;i<=n;i++){if(F[i]){while((getline l<F[i])>0){if(i==1){A[++j]=l}else{++k;if(k>j)k=1;if(length(A[k])<m){s=substr(l,length(l),1);A[k]=A[k]\"\"s;}}}}};for(i=1;i<=j;i++)print A[i]}" >m_A.txt
复制代码

TOP

本帖最后由 aloha20200628 于 2025-3-10 17:23 编辑

回复 1# 思想之翼

也给一个 python 版本
第一题型》生成35个分割文件(存为 test1.py 与  A.txt 源文件同目录运行)
  1. from itertools import combinations
  2. with open('A.txt', 'r') as fr: all = fr.readlines()
  3. for l in (list(combinations(range(1,8),4))):
  4. with open((ln:=''.join([str(i) for i in l]))+'.txt', 'w') as fw:
  5. for s in all: fw.write(s[int(ln[0])-1]+s[int(ln[1])-1]+s[int(ln[2])-1]+s[int(ln[3])-1]+'\n')
复制代码
第二题型》复原源文件的副本 AA.txt(存为 test2.py 运行,须基于 test1.py 的运行结果-即35个分割文件已经产生)
  1. with open('1234.txt', 'r') as fr: a1 = fr.readlines()
  2. with open('4567.txt', 'r') as fr: a2 = fr.readlines()
  3. with open('AA.txt', 'w') as fw:
  4. for n in range(len(a1)): fw.write(a1[n].strip()+a2[n][1:])
复制代码
1

评分人数

TOP

python也没有很方便
  1. from itertools import combinations
  2. with open('a.txt', 'r') as f:
  3.     a = f.readlines()
  4. for i in combinations(range(len(a[0].strip())), 4):
  5.     n = ''.join([a[0][j] for j in i])
  6.     with open(n + '.txt', 'w') as f:
  7.         f.writelines(map(lambda x: ''.join([x[j] for j in i]) + '\n', a))
复制代码
拼回来
  1. import os
  2. import re
  3. a = {}
  4. for i in os.listdir('.'):
  5.     if re.match(r'\d+\.txt', i):
  6.         with open(i, 'r') as f:
  7.             t = f.readlines()
  8.             for j in range(len(t[0].strip())):
  9.                 if i[j] in a:
  10.                     continue
  11.                 a[i[j]] = list(map(lambda x: x[j], t))
  12. k = sorted([i for i in a.keys()])
  13. with open('b.txt', 'w') as f:
  14.     f.writelines(map(lambda y:''.join(y) + '\n', zip(*map(lambda x:a[x], k))))
复制代码
1

评分人数

TOP

修复第25行下标不正确(越界)
QQ: 458609586
脚本优先 [PowerShell win10]

TOP

本帖最后由 xczxczxcz 于 2025-3-8 18:17 编辑

回复 4# 思想之翼


    若非 hawk :
给你来个 “大的”
  1. class CombineDigitHelper{
  2. [string]$directory; # a.txt; b.log;
  3. [string]$SplitDirectory; # 1234.txt; 1235.txt ...
  4. [object[]]$comb;        # 组合
  5. # 指定分割文本和总文本的目录
  6. CombineDigitHelper([string]$dir){
  7. if(![IO.Directory]::Exists($dir)){
  8. [IO.Directory]::CreateDirectory($dir);
  9. }
  10. $this.directory=$dir;
  11. $this.comb=@();
  12. $this.SplitDirectory=[IO.Path]::Combine($this.directory, "Split");
  13. if(![IO.Directory]::Exists($this.SplitDirectory)){
  14. [IO.Directory]::CreateDirectory($this.SplitDirectory);
  15. }
  16. }
  17. # 分割文件的组合,分割时要先运行此方法
  18. [void] CombDigit([string]$file, [int]$sel){
  19. $_f=[IO.Path]::Combine($this.directory, $file);
  20. $_o=[string[]](Get-Content $_f -ReadCount 0);
  21. $obj=1..$_o[0].Length;
  22. $select=[int[]]::new($sel);
  23. 0..($sel-1)|ForEach-Object{$select[$_]=$_}
  24. while($true){
  25. $str="";
  26. for($i=0; $i -lt $sel; $i++){$str+=$obj[$select[$i]].ToString()}
  27. $this.comb+=$str;
  28. if($select[$sel-1] -lt $obj.length-1){$select[$sel-1]++}
  29. else{
  30. $p=$sel-1;
  31. while(($p -gt 0) -and ($select[$p-1] -eq $select[$p]-1)){$p--}
  32. if($p -eq 0) {break;}
  33. $select[$p-1]++;
  34. for($j=$p; $j -lt $sel; $j++){
  35. $select[$j] =$select[$j-1]+1;
  36. }
  37. }
  38. }
  39. }
  40. # 制作总文本并指定每行为7个字符
  41. [void] MakeContent([string]$file, [int]$count){
  42. $this.MakeContent($file, $count, 7);
  43. }
  44. # 制作总文本并指定每行为任意个字符
  45. [void] MakeContent([string]$file, [int]$count, [int]$tol){
  46. # $source=[string[]]("1234567890abcdefghijklmnopqrstuvwxyz".ToCharArray());
  47. $source=1..9;
  48. $destfile=[IO.Path]::Combine($this.directory, $file);
  49. [IO.File]::CreateText($destfile).Close();
  50. for($i=0;$i-lt$count;$i++){
  51. $data=Get-Random -InputObject $source -Count $tol;
  52. Add-Content $destfile -Value (-join($data)) -Encoding Default -Force;
  53. }
  54. }
  55. # 分割文本
  56. [void] SplitContent([string]$sourceFile){
  57. if($this.comb.Length -eq 0){
  58. Write-Host '先生成文件组合再分割' -fore red;
  59. return;
  60. }
  61. $a=[IO.Path]::Combine($this.directory, $sourceFile);
  62. $Atxt=[string[]](Get-Content $a -ReadCount 0);
  63. foreach($txt in $this.comb){
  64. $file=[IO.Path]::Combine($this.SplitDirectory, "$txt.log");
  65. [IO.File]::CreateText($file).Close();
  66. $sb=[Text.StringBuilder]::new();
  67. for($j=0;$j -lt $Atxt.Length; $j++){
  68. if($Atxt[$j] -match '^$'){continue;}
  69. [string]$line="";
  70. for($i=0; $i -lt $txt.length; $i++){
  71. [int]$_i=[string]$txt[$i];
  72. $line+=$Atxt[$j][$_i-1];
  73. }
  74. [void]$sb.Append($line+"`r`n");
  75. }
  76. Set-Content $file -Value $sb.ToString().Trim() -Enc Default -NoNewline -Force;
  77. }
  78. }
  79. # 合并文本
  80. [void] MergeToFile([string]$destFile){
  81. $file=[IO.Path]::Combine($this.directory, $destFile);
  82. $outContentArr=@();
  83. $logs=[IO.Directory]::GetFiles($this.SplitDirectory, "*.log");
  84. $max=[Collections.Generic.HashSet[object]]($logs.Foreach{(Get-Item $_).BaseName.ToCharArray()});
  85. foreach($log in $logs){
  86. $bName=[string]([IO.Path]::GetFileNameWithoutExtension($log));
  87. $content=[string[]](Get-Content $log -ReadCount 0);
  88. if($outContentArr.Count -eq 0){
  89. for($i=0; $i -lt $content.Length; $i++){
  90. $outContentArr+=,[string[]]::new($max.Count);
  91. }
  92. $max.Clear();
  93. }
  94. for($i=0;$i -lt $content.Length;$i++){
  95. for($a=0; $a -lt $bName.Length; $a++){
  96. [int]$t=[string]$bName[$a]
  97. if(![string]::IsNullOrEmpty($outContentArr[$i][$t-1])){continue}
  98. $outContentArr[$i][$t-1]=$content[$i][$a];
  99. }
  100. }
  101. }
  102. $_out=@($outContentArr.ForEach{-join($_)}) -join "`r`n";
  103. Set-Content $file -Value $_out -Encoding Default -NoNewline  -Force;
  104. }
  105. # 删除合并文本和分割文本及相关目录
  106. [void] ClearTxt([bool]$delSubDir){
  107. if($null -ne $this.comb){$this.comb.Clear()}
  108. $this.comb=$null;
  109. try{
  110. [IO.Directory]::Delete($this.SplitDirectory, $true);
  111. [IO.Directory]::Delete($this.directory, $delSubDir);
  112. }catch{}
  113. }
  114. }
  115. # 食用,不要把脚本放在制作目录中 ;实例化,换成自己的目录
  116. $comb=[CombineDigitHelper]::new("F:\WinTemp\Temp\Combine\");
  117. # 生成随机数创建A.txt 1000=行数 8=每行字符数,默认为7,有现存的则不执行此句
  118. $comb.MakeContent("a.txt", 1000); # $comb.MakeContent("a.txt", 1000, 8);
  119. # 下面的方法按需要运行
  120. # 分割文本 4=按4个字符组合
  121. $comb.CombDigit("a.txt", 4);
  122. $comb.SplitContent("a.txt");
  123. # 合并文件
  124. $comb.MergeToFile("b.txt");
  125. # 清除文件,会清除所有文件,注意备份
  126. $comb.ClearTxt($false);
复制代码
1

评分人数

QQ: 458609586
脚本优先 [PowerShell win10]

TOP

贴一个问题1的解决方案(非gawk)
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. rem 定义所有四元组组合
  4. set combinations=1234 1235 1236 1237 1245 1246 1247 1256 1257 1267 1345 1346 1347 1356 1357 1367 1456 1457 1467 1567 2345 2346 2347 2356 2357 2367 2456 2457 2467 2567 3456 3457 3467 3567 4567
  5. rem 清空现有输出文件
  6. for %%C in (%combinations%) do if exist %%C.txt del %%C.txt
  7. rem 逐行处理A.txt
  8. for /f "usebackq delims=" %%L in ("A.txt") do (
  9.     set "line=%%L"
  10.     for %%C in (%combinations%) do (
  11.         set "pos=%%C"
  12.         rem 提取四个位置索引
  13.         set /a i1=!pos:~0,1!-1
  14.         set /a i2=!pos:~1,1!-1
  15.         set /a i3=!pos:~2,1!-1
  16.         set /a i4=!pos:~3,1!-1
  17.         rem 截取字符并拼接
  18.         for %%a in (!i1!) do set "c1=!line:~%%a,1!"
  19.         for %%a in (!i2!) do set "c2=!line:~%%a,1!"
  20.         for %%a in (!i3!) do set "c3=!line:~%%a,1!"
  21.         for %%a in (!i4!) do set "c4=!line:~%%a,1!"
  22.         echo !c1!!c2!!c3!!c4!>>%%C.txt
  23.     )
  24. )
  25. endlocal
复制代码

TOP

问题2麻烦之处在于楼主要求输出的文件没有顺序 ,在不知道原本内容情况下无法确定文件顺序(不知道怎么确认)
但是如果输出的文件是1.txt , 2.txt ,3.txt ,4.txt ,5.txt ,6.txt ,7.txt .... ,35.txt的话
文件名已经明确了顺序 ,7组合4的情况下 ,只需要前4个文件就行了(即1.txt , 2.txt ,3.txt ,4.txt)
取1.txt的每一行跟2.txt ,3.txt ,4.txt每一行的最后一个就是了

TOP

不知行否
问题一
批处理文件中
默认换行符
  1. gawk "function fff(a,b,c,d,e){X[x]=c;Y[y]=d;Z[z]=e;for(C[i]=Y[y];C[i]<=a-1;C[i]++){t=Z[z]\"\"B[C[i]+1];if(length(t)==b){if(u){++m;o=m%%n;print t>>D[o]\".txt\"}else{D[n++]=t;print t>t\".txt\"}}else{l=C[i]+1;x++;y++;z++;i++;fff(a,b,c,l,t)}};x--;y--;z--;i--;};BEGIN{u=0}{split($0,A,/./,B);fff(7,4,1,0,\"\");u++}" A.txt
复制代码
1

评分人数

TOP

返回列表