标题: [文本处理] 【已解决】求教:gawk 按字节拆分数据的运用 [打印本页]
作者: 思想之翼 时间: 2023-2-25 09:50 标题: 【已解决】求教:gawk 按字节拆分数据的运用
本帖最后由 思想之翼 于 2023-2-25 20:19 编辑
- "C:\SoftWare\gawk.exe" -F"=" "NR==FNR{A[$1]=$2;next}{print A[$0]}" "D:\00\a.txt" "D:\11\b.txt">"D:\22\c.txt"
复制代码
上列代码,将一组6位数按照1 3 5字节,拆分成1个文本。
现在有一组32位数,格式如下:
12345678123456781234567812345678
87654321876543218765432187654321
欲按每5个字节一组拆分,共拆分成201376个文本,结果如下:
000001.txt
12345
87654
000002.txt
12346
87653
000003.txt
12347
87652
...
201376.txt
45678
54321
作者: hfxiang 时间: 2023-2-25 11:21
本帖最后由 hfxiang 于 2023-2-25 11:38 编辑
- gawk -vFPAT="[0-9]" "{for(i=0;i++<NF;){a[NR,i]=$i}}END{for(i=4;++i<=NF;){for(j=i;j<=NF;j++){fn=sprintf(\"%06d.txt\",++n);print a[1,i-4]a[1,i-3]a[1,i-2]a[1,i-1]a[1,j]\"\n\"a[2,i-4] a[2,i-3] a[2,i-2] a[2,i-1] a[2,j]\"\n\">fn;close(fn)}}}" a.txt
复制代码
作者: 思想之翼 时间: 2023-2-25 11:37
回复 2# hfxiang
感谢!双击运行无反应啊
作者: hfxiang 时间: 2023-2-25 11:41
回复 3# 思想之翼
俺反复测试后才上传的。能把你的具体操作过程表达一下吗?以便问题查找
作者: 思想之翼 时间: 2023-2-25 13:17
回复 4# hfxiang
a.txt gawk.exe chaifen.bat 放一个文件夹
出错图片及压缩文件上传不了,抓取了部分文字:
gawk:cmd.line:1:warning:escape sequence '\'treated as plain ''
gawk:cmd.line:1:warning:escape sequence '\'treated as plain ''
gawk:cmd.line:1:warning:escape sequence '\c'treated as plain '\c'
gawk:cmd.line:1:warning:escape sequence '\'treated as plain ''
gawk:cmd.line:1:<FILENAME=a.txt FNR=2>fatal:can't redirect to E:\201376\5chaifen\201376.bat6d.txt'<Invalid argument>
作者: hfxiang 时间: 2023-2-25 13:33
回复 5# 思想之翼
把chaifen.bat放上来看看
作者: 思想之翼 时间: 2023-2-25 14:12
回复 6# hfxiang - gawk -vFPAT="[0-9]" "{for(i=0;i++<NF;){a[NR,i]=$i}}END{for(i=4;++i<=NF;){for(j=i;j<=NF;j++){fn=sprintf(\"%06d.txt\",++n);print a[1,i-4]a[1,i-3]a[1,i-2]a[1,i-1]a[1,j]\"\n\"a[2,i-4] a[2,i-3] a[2,i-2] a[2,i-1] a[2,j]\"\n\">fn;close(fn)}}}" a.txt
复制代码
chaifen.bat 代码如上
作者: hfxiang 时间: 2023-2-25 16:02
回复 7# 思想之翼
估计是版本问题,把单个“%”改为双“%%”试试,具体如下:- gawk -vFPAT="[0-9]" "{for(i=0;i++<NF;){a[NR,i]=$i}}END{for(i=4;++i<=NF;){for(j=i;j<=NF;j++){fn=sprintf(\"%%06d.txt\",++n);print a[1,i-4]a[1,i-3]a[1,i-2]a[1,i-1]a[1,j]\"\n\"a[2,i-4] a[2,i-3] a[2,i-2] a[2,i-1] a[2,j]\"\n\">fn;close(fn)}}}" a.txt
复制代码
作者: WHY 时间: 2023-2-25 16:21
本帖最后由 WHY 于 2023-3-3 15:59 编辑
PowerShell 脚本,保存为Test.ps1,右键使用PowerShell运行
运行之前把杀软的文件实时监控关掉,否则频繁的磁盘操作CPU会达到100%,也会拖慢脚本速度
2023/03/03修改,假定每一行数据长度都相同,先创建一个N选M组合的索引表,每行数据按表搜索。- $MyPath = $MyInvocation.MyCommand.Path -replace '\\[^\\]*$', '\'; #脚本自身路径
- $srcFile = $MyPath + '1.txt'; #源文件
- $dstFolder = $MyPath + 'result'; #目标目录
-
- If (![IO.Directory]::Exists($dstFolder)){
- $null = md $dstFolder;
- }
-
- Function Get-Combination($n, $m){
- $key = 1;
- $str = '1' * $m + '0' * ($n-$m); #11111000000000000000000000000000 共32位
- $m = [regex]::Matches($str, '1');
- $Hash.Add($key, $m.Index); #HashTable赋初始值
- while ($str.IndexOf('10') -ge 0) {
- $str = $str -replace '10(?>(0*))(?>(1*))$', '01$2$1'; #交换 10 <--> 01
- $m = [regex]::Matches($str, '1');
- $Hash.Add(++$key, $m.Index); #HashTable赋值
- }
- }
-
- Function Set-ContentToFile($oDict){
- forEach($key In $oDict.Keys){
- $dstFile = $dstFolder + '\' + (''+$key).PadLeft(6, '0') + '.txt'; #目标文件名
- [IO.File]::AppendAllText($dstFile, $oDict[$key], [Text.Encoding]::Default); #写入文件
- }
- }
-
- $Hash = New-Object System.Collections.HashTable;
- $n = 32; $m = 5; #32选5组合
- Get-Combination $n $m #创建索引表,存放到$Hash中
-
- $arr = [IO.File]::ReadAllLines($srcFile, [Text.Encoding]::Default); #读源文本
- $dic = New-Object 'System.Collections.Generic.Dictionary[int, string]'; #字典,存放结果
- $num = 0;
-
- for($i=0; $i -lt $arr.Count; $i++){
- $chr = [char[]]$arr[$i]; #转成字符数组
- forEach( $key In $Hash.Keys ){ #遍历索引表
- $s = '';
- for ($j = 0; $j -lt $m; $j++){
- $index = $Hash[$key][$j];
- $s += $chr[$index];
- }
- If (!$dic.ContainsKey($key)) { $dic.Add($key, ''); }
- $dic[$key] += $s + "`r`n"; #字典赋值
- }
- If (++$num % 2 -eq 0){ #每读取2行数据开始写入文件
- Set-ContentToFile $dic;
- $dic.Clear(); #清空字典
- }
- }
-
- If ($dic.Count -gt 0){ #字典不为空,写入文件
- Set-ContentToFile $dic;
- }
-
- echo 'DONE';
- [Console]::ReadLine();
复制代码
作者: WHY 时间: 2023-2-25 16:28
本帖最后由 WHY 于 2023-2-27 14:47 编辑
我也来个 gawk- @echo Off
- md Result 2>nul
- gawk "BEGIN{FS=\"\"}{n=0;for(i=1;i<=NF-4;i++)for(j=i+1;j<=NF-3;j++)for(k=j+1;k<=NF-2;k++)for(L=k+1;L<=NF-1;L++)for(m=L+1;m<=NF;m++){++n;a[n]=a[n]$i$j$k$L$m\"\n\"}}END{for(i=1;i<=length(a);i++){f=\"Result/\"substr(1000000+i,2)\".Log\";printf a[i]>f;close(f)}}" 1.txt
- pause
复制代码
发现加上close(),关闭文件句柄速度会快很多。
作者: 思想之翼 时间: 2023-2-25 16:29
本帖最后由 思想之翼 于 2023-2-25 17:02 编辑
回复 8# hfxiang
感谢!能够运行,但结果不对。32位数,每5个字节组成一组,有201376种组合。
作者: hfxiang 时间: 2023-2-25 16:57
回复 11# 思想之翼
没能看明白题意,抱歉
作者: 思想之翼 时间: 2023-2-25 17:02
回复 12# hfxiang
非常感谢您的帮助!
作者: Batcher 时间: 2023-2-25 22:20
回复 5# 思想之翼
如果需要上传文件,可以用阿里云盘或百度网盘。
如果需要上传截图,可以找个图床,例如:
http://bbs.bathome.net/thread-60985-1-1.html
作者: terse 时间: 2023-2-25 22:30
这类组合类问题 主要效率上不去啊
作者: WHY 时间: 2023-2-25 23:07
回复 15# terse
是的,磁盘IO性能好的话,速度可能会快一点。
20万个文件频繁读写,时间都浪费在写磁盘上了。
在我的电脑上,机械硬盘,PS脚本大概62秒,GAWK很慢,我没敢测试。
作者: WHY 时间: 2023-2-28 15:12
Test.vbs- Dim myPath, srcFile, dstFolder
- myPath = Left(WSH.ScriptFullName, InStrRev(WSH.ScriptFullName, "\")) '脚本所在路径
- srcFile = myPath & "1.txt" '源文本文件
- dstFolder = myPath & "result" '目标目录
-
- Dim fso
- Set fso = CreateObject("Scripting.FileSystemObject")
- If Not fso.FolderExists(dstFolder) Then fso.CreateFolder(dstFolder) '创建目标目录
-
- Dim c, objDic, objFile
- c = 5 'N选5组合
- Set objDic = CreateObject("Scripting.Dictionary") '字典,存放结果
- Set objFile = fso.OpenTextFile(srcFile, 1) '打开源文本文件
-
- While Not objFile.AtEndOfStream
- Dim strLine
- strLine = objFile.ReadLine '逐行读取源文件
- GetCombination strLine '调用函数
- Wend
- objFile.Close
-
- Dim dstFile, f
- For Each key In objDic.Keys
- dstFile = dstFolder & "\" & Right("000000" & key, 6) & ".txt" '目标文件名
- Set f = fso.OpenTextFile(dstFile, 2, True)
- f.Write(objDic.Item(key)) '写入目标文件
- f.Close
- Next
-
- Function GetCombination(strLine)
- Dim key, str, i
- key = 1
- str = ""
- For i = 1 To Len(strLine) 'str赋值:11111000000000000000000000000000 共32位
- If i <= c Then
- str = str & "1"
- Else
- str = str & "0"
- End If
- Next
-
- If Not objDic.Exists(key) Then objDic.Add key, ""
- objDic.Item(key) = objDic.Item(key) & Left(strLine, c) & vbCrLf '字典,赋初始值
-
- Dim reg
- Set reg = New RegExp '创建正则表达式
- reg.Pattern = "(1)(0)(?=(0*))\3(?=(1*))\4$"
-
- While InStr(str, "10") > 0
- Dim s
- s = ""
- str = reg.Replace(str, "$2$1$4$3") 'str值交换 10 <--> 01
- For i = 1 To Len(str)
- If Mid(str, i, 1) = "1" Then s = s & Mid(strLine, i, 1) '查找"1"与strLine对应的字符
- If Len(s) = c Then Exit For '找到5个,退出For
- Next
- key = key + 1
- If Not objDic.Exists(key) Then objDic.Add key, ""
- objDic.Item(key) = objDic.Item(key) & s & vbCrLf '字典,赋值
- Wend
- End Function
-
- MsgBox "Done"
复制代码
作者: 思想之翼 时间: 2023-2-28 16:52
回复 9# WHY
感谢!
经过测试,该 PowerShell 脚本,处理十几行的数据非常迅速,但处理成千上万行数据,读入内存的耗时让人崩溃。
欲提高 PowerShell 脚本的效率,研究过类似下列网页的文章,还是不得要领,恳望指点。
https://www.pstips.net/speeding-up-powershell-multithreading.html
作者: 思想之翼 时间: 2023-2-28 17:04
回复 17# WHY
感谢!
处理成千上万行数据,同样存在读入内存耗时漫长的状况。
作者: WHY 时间: 2023-2-28 23:41
本帖最后由 WHY 于 2023-3-3 16:12 编辑
回复 18# 思想之翼
这个问题得看电脑硬件配置了,我的电脑配置不咋地,多线程没想去玩。
每一行数据要循环处理201376次,然后又要写磁盘201376次,如果有10000行数据,别指望能快到哪去。
改一下,每读取2行数据开始写磁盘,减少循环等待时间及字典空间占用,我没有过多测试。你试试吧。- Dim myPath, srcFile, dstFolder
- myPath = Left(WSH.ScriptFullName, InStrRev(WSH.ScriptFullName, "\")) '脚本所在路径
- srcFile = myPath & "1.txt" '源文本文件
- dstFolder = myPath & "result" '目标目录
-
- Dim fso
- Set fso = CreateObject("Scripting.FileSystemObject")
- If Not fso.FolderExists(dstFolder) Then fso.CreateFolder(dstFolder) '创建目标目录
-
- Dim c, objDic, objFile
- c = 5 'N选5组合
- Set objDic = CreateObject("Scripting.Dictionary") '字典,存放结果
- Set objFile = fso.OpenTextFile(srcFile, 1) '打开源文件
-
- Dim num, strLine
- num = 0
- While Not objFile.AtEndOfStream
- num = num + 1
- strLine = objFile.ReadLine '逐行读取源文件
- GetCombination strLine, c, objDic '求组合
- If num Mod 2 = 0 Then '每读取2行开始写入文件
- SaveToFile objDic
- objDic.RemoveAll '清空字典
- End If
- Wend
- If objDic.Count > 0 Then SaveToFile objDic '字典不为空,写入文件
- objFile.Close
-
- Function SaveToFile(ByRef oDict)
- Dim key, dstFile, f
- For Each key In oDict.Keys
- dstFile = dstFolder & "\" & Right("000000" & key, 6) & ".txt" '目标文件名
- Set f = fso.OpenTextFile(dstFile, 8, True)
- f.Write(oDict.Item(key)) '写入目标文件
- f.Close
- Next
- End Function
-
- Function GetCombination(ByRef strLine, c, ByRef oDict)
- Dim key, str, i
- key = 1
- str = ""
- For i = 1 To Len(strLine) 'str赋值:11111000000000000000000000000000 共32位
- If i <= c Then
- str = str & "1"
- Else
- str = str & "0"
- End If
- Next
-
- If Not oDict.Exists(key) Then oDict.Add key, ""
- oDict.Item(key) = oDict.Item(key) & Left(strLine, c) & vbCrLf '字典,赋初始值
-
- Dim reg
- Set reg = New RegExp '创建正则表达式
- reg.Pattern = "10(?=(0*))\1(?=(1*))\2$"
-
- While InStr(str, "10") > 0
- Dim s
- s = ""
- str = reg.Replace(str, "01$2$1") 'str值交换 10 <--> 01
- For i = 1 To Len(str)
- If Mid(str, i, 1) = "1" Then s = s & Mid(strLine, i, 1) '查找"1"与strLine对应的字符
- If Len(s) = c Then Exit For '找到5个,退出For
- Next
- key = key + 1
- If Not oDict.Exists(key) Then oDict.Add key, ""
- oDict.Item(key) = oDict.Item(key) & s & vbCrLf '字典,赋值
- Wend
- End Function
-
- MsgBox "Done"
复制代码
欢迎光临 批处理之家 (http://www.bathome.net/) |
Powered by Discuz! 7.2 |