Board logo

标题: [文本处理] 批处理如何对文本里各列数据分别除以指定数值 [打印本页]

作者: meiszp    时间: 2016-9-27 14:01     标题: 批处理如何对文本里各列数据分别除以指定数值

本帖最后由 meiszp 于 2016-9-29 11:18 编辑

文件夹下有许多数据文件(扩展名为txt或指定),文件内容为多列数据(下面为7列,但实际可能更多),想对每列除以一个数,比如第1列除以10,第2列除以20等等。
求大侠赐教。

-6.70552254e-007  4.56646750e+005  6.89739219e+004 -3.81691500e+005  2.08684141e+005 -4.90864719e+005  3.10406906e+005
  5.00000007e-002  4.61931250e+005  1.36446094e+005 -3.59222750e+005  2.07390922e+005 -4.75073250e+005  3.40052250e+005
  9.99993235e-002  4.98387563e+005  2.60942938e+005 -3.52485344e+005  2.02917281e+005 -4.60640719e+005  3.66940344e+005
  1.50000006e-001  5.08161344e+005  3.97039625e+005 -3.58057656e+005  1.97205422e+005 -4.43923438e+005  3.92823375e+005
  1.99999332e-001  4.81562063e+005  5.06175219e+005 -3.86291063e+005  1.91434969e+005 -4.22848281e+005  4.17620406e+005
  2.50000000e-001  4.46009031e+005  5.63322500e+005 -4.38631031e+005  1.88274859e+005 -3.97913656e+005  4.41026063e+005
  2.99999326e-001  4.34343250e+005  5.40127375e+005 -4.90687344e+005  1.88438328e+005 -3.70999531e+005  4.62318875e+005
  3.49999994e-001  4.58196469e+005  4.70192063e+005 -5.18217250e+005  1.90427172e+005 -3.43401031e+005  4.79834125e+005
  3.99999321e-001  4.85120313e+005  3.84186875e+005 -5.56579813e+005  1.93310938e+005 -3.15954906e+005  4.95534531e+005


数据文件见网盘 http://share.weiyun.com/6bdcb931f8703b3830a9c9d711f5e053
作者: pcl_test    时间: 2016-9-27 14:54

本帖最后由 pcl_test 于 2016-9-29 23:40 编辑
  1. #*第三方http://www.bathome.net/s/tool/index.html?key=gawk
  2. #*&cls&dir /a-d/b *.txt|gawk -f "%~f0"&pause&exit
  3. BEGIN{
  4.     folder="结果";
  5.     system("md \""folder"\" 2>nul");
  6.     list="1=10,2=20,3=30,4=40,5=50,6=60,7=70,8=80,9=90,10=100,11=110,12=120";
  7.     #此处定义每列的除数,如1=10表示第1列除以10,2=20表示第2列除以20……以此类推,
  8.     #只要定义到最大的列即可,如最多有20列,则定义到20=除数,
  9.     #如果不对某列操作,则该列不需定义除数或定义除数为1
  10.     split(list,a,",");
  11.     for(i=1;i<=length(a);i++){
  12.         split(a[i],b,"=");
  13.         map[b[1]]=b[2];
  14.     }
  15.     while(getline file>0){
  16.         while(getline<file>0){
  17.             if($0~/^[[:space:]]*$/){
  18.                 print>folder"\\New_"file;
  19.             }else{
  20.                 for(i=1;i<=NF;i++){
  21.                     printf i<NF?"%.8e  ":"%.8e\n",map[i]==""?$i:$i/map[i]>folder"\\New_"file;
  22.                 }
  23.             }
  24.         }
  25.     }
  26. }
复制代码

作者: meiszp    时间: 2016-9-27 15:38

本帖最后由 meiszp 于 2016-9-27 15:47 编辑

回复 2# pcl_test
恕我小白,请问第一行是要我安装gawk?第二行是让我在DOS窗口复制下面命令运行吗?
&cls&dir /a-d/b *.txt|gawk -f "%~f0"&pause&exit
有没有纯批的命令呢?谢谢!
作者: pcl_test    时间: 2016-9-27 19:24

本帖最后由 pcl_test 于 2018-4-12 15:08 编辑
  1. powershell -c "dir *.txt|?{$_ -is [IO.FileInfo]}|%%{gc $_|%%{$a=($_.trim() -split '\s+');('{0:e8} {1:e8} ' -f ($a[0]/10),($a[1]/20))+($a[2..($a.length-1)] -join ' ')}|out-file ('New_'+$_.name) -encoding default}"
  2. pause
复制代码

作者: 523066680    时间: 2016-9-27 19:58

本帖最后由 523066680 于 2016-9-27 20:11 编辑

Perl,安装请咨询搜索引擎。
  1. open READ, "<:raw", "data.txt";
  2. my @divi = map { $_ * 10 } (1 .. 20);  #10 20 30 ... 200
  3. my $i;
  4. while ($e = <READ> )
  5. {
  6.     $e =~s/^\s+//;      #开头空格清除
  7.     $e =~s/\r?\n$//;    #换行符清除
  8.     $i = 0;
  9.     @arr =  map { $divi[$i++] * $_  } split(/\s+/, $e);
  10.     grep { printf("% e  ", $_) } @arr;
  11.     print "\n";
  12. }
  13. close READ;
复制代码
相比之下我这个有点肿,可能有些知识没掌握
输出结果没有验证过
  1. -6.705523e-006   9.132935e+006   2.069218e+006  -1.526766e+007   1.043421e+007  -2.945188e+007   2.172848e+007  
  2. 5.000000e-001   9.238625e+006   4.093383e+006  -1.436891e+007   1.036955e+007  -2.850440e+007   2.380366e+007  
  3. 9.999932e-001   9.967751e+006   7.828288e+006  -1.409941e+007   1.014586e+007  -2.763844e+007   2.568582e+007  
  4. 1.500000e+000   1.016323e+007   1.191119e+007  -1.432231e+007   9.860271e+006  -2.663541e+007   2.749764e+007  
  5. 1.999993e+000   9.631241e+006   1.518526e+007  -1.545164e+007   9.571748e+006  -2.537090e+007   2.923343e+007  
  6. 2.500000e+000   8.920181e+006   1.689968e+007  -1.754524e+007   9.413743e+006  -2.387482e+007   3.087182e+007  
  7. 2.999993e+000   8.686865e+006   1.620382e+007  -1.962749e+007   9.421916e+006  -2.225997e+007   3.236232e+007  
  8. 3.500000e+000   9.163929e+006   1.410576e+007  -2.072869e+007   9.521359e+006  -2.060406e+007   3.358839e+007  
  9. 3.999993e+000   9.702406e+006   1.152561e+007  -2.226319e+007   9.665547e+006  -1.895729e+007   3.468742e+007  
复制代码

作者: happy886rr    时间: 2016-9-27 21:58

本帖最后由 happy886rr 于 2016-9-28 22:41 编辑

回复 1# meiszp
纯批模拟科学计数法
  1. @echo off
  2. SETLOCAL ENABLEDELAYEDEXPANSION
  3. (for /f "tokens=1,2,*" %%a in ('type test.txt') do (
  4. for /f "tokens=1,2 delims=e" %%A in ("%%a") do (
  5. set "str=%%B"
  6. if "!str:~0,1!"=="-" (
  7. set/a "str=1!str:~1!+1"&set "str=-!str:~-3!"
  8. ) else (
  9. if "!str!"=="+000"   (
  10. set "str=-001"
  11. ) else (
  12. set/a "str=1!str:~!-1"&set "str=+!str:~-3!"
  13. )
  14. )
  15. set "lie1=  %%Ae!str!"
  16. )
  17. for /f "tokens=1,2 delims=e" %%A in ("%%b") do (
  18. set "str=%%B"&set "ptr=%%A"&set "ptr=!ptr:.=!"
  19. if !ptr! geq 200000000 (set/a ptr/=2) else (set/a ptr=!ptr!0/2)
  20. if !ptr! geq 500000000 (set Mark=1) else (set Mark=0)
  21. if "!str:~0,1!"=="-" (
  22. set/a "str=1!str:~!+1+Mark"&set "str=-!str:~1!"
  23. ) else (
  24. if "!str!"=="+000"   (
  25. if !Mark! equ 1 (set "str=-001") else (set "str=-002")
  26. ) else (
  27. set/a "str=1!str:~1!-1-Mark"&set "str=+!str:~1!"
  28. )
  29. )
  30. set "lie2=  !ptr:~0,1!.!ptr:~1!e!str!"
  31. )
  32. echo !lie1:~-16! !lie2:~-16! %%c
  33. ))>new.txt
  34. start new.txt
  35. set/p=修改完毕!
复制代码

作者: codegay    时间: 2016-9-28 06:02

按CSV文件的格式存文件,保持格式统一。不要为了视觉对齐,用空格补全对齐文件内容。
作者: WHY    时间: 2016-9-28 19:43

PowerShell
  1. $str = [IO.File]::ReadAllText('D:\Test\a.txt', [Text.Encoding]::Default);
  2. [regex]::Replace($str, '(?m)^(\s*\S+)', {param($m); ($m.Value/10).ToString('e8')})
复制代码

作者: meiszp    时间: 2016-9-28 22:21

本帖最后由 pcl_test 于 2016-9-28 22:27 编辑

回复 4# pcl_test

大神,您好!您写的大代码我复制新建了个.bat文件运行,结果如下。多了一列,结果也不是我想要的。还有就是每列都要除以一个数字,比如共有20列,1列/1、2列/2、3列/3……20列/20。
作者: meiszp    时间: 2016-9-28 22:22

回复 5# 523066680

谢谢,小白还是喜欢纯批,不用安装其他东西。
作者: pcl_test    时间: 2016-9-28 22:23

回复 9# meiszp
把你测试的文本打包发上来看看
作者: meiszp    时间: 2016-9-28 22:27

回复 11# pcl_test
不在自己的电脑上,我明天上传吧。麻烦大神了。
作者: meiszp    时间: 2016-9-28 22:27

回复 6# happy886rr
谢谢!完全看不懂。在代码中看不出我要除的数字。您写的大代码我复制新建了个.bat文件运行,没有结果。
作者: meiszp    时间: 2016-9-28 22:29

回复 8# WHY
谢谢!不过每列没有除以一个数。
作者: happy886rr    时间: 2016-9-28 22:30

本帖最后由 happy886rr 于 2016-9-28 22:39 编辑

回复 13# meiszp
没有结果那就对了,我只修改名字为test.txt的文件,对了,我还没有加pause。速度太快,结果一闪而过。已添加pause,请在原楼复制吧。
作者: pcl_test    时间: 2016-9-28 22:31

回复 12# meiszp
不用了,你就用你顶楼的数据测试,每行开头的空格去掉,不知你原数据每行开头是否空格?
作者: meiszp    时间: 2016-9-28 22:42

本帖最后由 pcl_test 于 2018-4-12 15:09 编辑

回复 16# pcl_test

是空格的原因,试验了下没有问题,不过不记得有没有空格, 明天看看。
还有大神,我举的例子只对前两列除了个数,但有好多列
作者: happy886rr    时间: 2016-9-28 22:44

回复 17# meiszp
已添加打印输出,请到6楼重新复制。
作者: meiszp    时间: 2016-9-28 22:49

回复 18# happy886rr

谢谢,可以对例子实现。
但这个好像只能对文件名为test.txt的一个文件使用。我是有几百个这样的数据文件,每个文件有好多列,最多的是20列,每列可能都会除以一个不确定数,所以我要穷举出所以列。
作者: happy886rr    时间: 2016-9-28 22:52

回复 19# meiszp
抱歉,你什么参数都不确定,我也无能为力了。
作者: pcl_test    时间: 2016-9-28 22:54

本帖最后由 pcl_test 于 2018-4-12 15:10 编辑

回复 17# meiszp

只针对顶楼7列的数据有效
  1. powershell -c "dir 1.txt|?{$_ -is [IO.FileInfo]}|%%{gc $_|%%{$a=($_.Trim() -split '\s+');'{0:e8} {1:e8} {2:e8} {3:e8} {4:e8} {5:e8} {6:e8}' -f ($a[0]/10),($a[1]/20),($a[2]/30),($a[3]/40),($a[4]/50),($a[5]/60),($a[6]/70)}|out-file ('New_'+$_.name) -encoding default}"
  2. pause
复制代码

作者: meiszp    时间: 2016-9-28 22:58

回复 20# happy886rr

每列除的数可以先代替,用时自己修改。比如有20列,1列/1、2列/2、3列/3……20列/20。
如果有10列,是不是把代码里的20,也可能是个控制代码,修改到10,后面相应的1列/1、2列/2、3列/3……10列/10。
作者: WHY    时间: 2016-9-28 23:13

PowerShell
  1. $str = [IO.File]::ReadAllText('D:\Test\a.txt', [Text.Encoding]::Default);
  2. [regex]::Replace($str, "[^`r`n]+", {param($a); $i=0; [regex]::Replace($a.Value, '\S+', {param($b); ($b.Value/++$i).ToString('e8')})})
复制代码

作者: meiszp    时间: 2016-9-28 23:25

回复 21# pcl_test
谢谢!如果不是7列的话,应该是更改下面红色部分了。我试验了下没问题,非常感谢。
powershell -c "dir  *.txt|?{$_ -is [IO.FileInfo]}|%%{gc $_|%%{$a=($_.Trim() -split '\s+');'{0:e8} {1:e8} {2:e8} {3:e8} {4:e8} {5:e8} {6:e8}' -f ($a[0]/10),($a[1]/20),($a[2]/30),($a[3]/40),($a[4]/50),($a[5]/60),($a[6]/70)}|out-file ('New_'+$_.name) -encoding ascii}"
pause
作者: meiszp    时间: 2016-9-28 23:31

回复 23# WHY

谢谢!在D:\Test\a.txt下试用了下,没什么改变,没有对每列除以一个数。
作者: pcl_test    时间: 2016-9-29 00:02

本帖最后由 pcl_test 于 2018-4-12 15:10 编辑

$map=@{'0'=10;'1'=20;'2'=30;'3'=40;'4'=50;'5'=60;'6'=70;'7'=80;'8'=90;'9'=100;'10'=110;'11'=120;……}
此处定义每列的除数,如'0'=10表示第1列除以10,'1'=20表示第2列除以20……以此类推,只要定义到最大的列即可,如最多有20列,则定义到'19'=除数,如果不对某列操作,则该列不需定义除数或定义除数为1
  1. powershell -c "$map=@{'0'=10;'1'=20;'2'=30;'3'=40;'4'=50;'5'=60;'6'=70;'7'=80;'8'=90;'9'=100;'10'=110;'11'=120};dir *.txt|?{$_ -is [IO.FileInfo]}|%%{gc $_|%%{if($_ -match '^\s*$'){$_}else{$a=($_.trim() -split '\s+');$line='';for($i=0;$i -le ($a.length-1);$i++){if($map.ContainsKey(''+$i)){$line+='  '+('{0:e8}' -f ($a[$i]/$map[''+$i]))}else{$line+=' '+$a[$i]}};$line.trim()}}|out-file ('New_'+$_.name) -encoding default}"
  2. pause
复制代码

作者: /zhqsystem/zhq    时间: 2016-9-29 03:32

也许有错误,错误在计算方法上也许错误文化有限看不懂这个数值
一般可以看得懂代码和移位类似,支持超过for变量占用超出分列,但是不能超过最大变量字符数
只看方法吧
  1. @echo off&&setlocal enabledelayedexpansion
  2. set "[set]=10 20 30 40 50 60 80"
  3. for /l %%n in (1,1,8192)do (
  4. for /f "tokens=1,* delims= " %%i in ("![set]!")do (
  5.   set "[set]=%%j"&&set/a "[set][n]+=1"
  6.   for /f "delims=" %%n in ("![set][n]!")do set "[set][new][%%n]=%%i"
  7. )
  8. )
  9. for /f "delims=" %%i in ('type "新建文本文档 (4).txt"')do (
  10. set "[type]=%%i"&&set "[type][n]="&&set "[true]="
  11. for /l %%n in (1,1,![set][n]!)do (
  12.   for /f "tokens=1,* delims= " %%i in ("![type]!")do (
  13.    set "[type]=%%j"&&set/a "[type][n]+=1"
  14.    for /f "delims=" %%n in ("![type][n]!")do (
  15.     set "[calc]=%%i/![set][new][%%n]!"
  16.     call :[calc]
  17.     if defined [true] (
  18.      set "[true]=![true]! ![calc][new]!"
  19.     )else (
  20.      set "[true]=![calc][new]!"
  21.     )
  22.    )
  23.   )
  24. )
  25. echo/
  26. echo,![true]!
  27. )
  28. pause
  29. exit
  30. :[calc]
  31. for /f "delims=" %%c in ('mshta.exe "vbscript:createobject("scripting.filesystemobject").getstandardstream(1).write(%[calc]%)(close)"') do set "[calc][new]=%%~c"
  32. goto:eof
复制代码

作者: WHY    时间: 2016-9-29 10:01

这个帖子真的特么火了吗?
  1. @echo off
  2. set "r='\d+\.?\d*[Ee][-+]\d{3}'"
  3. md new\ 2>nul
  4. PowerShell -c "dir *.txt|%%{$str=[IO.File]::ReadAllText($_,[Text.Encoding]::Default);[regex]::Replace($str,\"[^^`r`n]+\",{param($a);$i=0;[regex]::Replace($a.Value,%r%,{param($b);($b.Value/++$i).ToString('e8')})})>('new\'+$_.Name)}"
  5. pause
复制代码

作者: codegay    时间: 2016-9-29 10:13

回复 27# /zhqsystem/zhq


   科学计数法
作者: 523066680    时间: 2016-9-29 10:39

本帖最后由 523066680 于 2016-9-29 10:41 编辑
回复  523066680

谢谢,小白还是喜欢纯批,不用安装其他东西。
meiszp 发表于 2016-9-28 22:22



    哈哈哈,这句话说的好任性,潜台词是:
小白还是喜欢各位大大用纯批处理帮我服务,不要安装其他东西,that's too easy,you guys must pay more time.
作者: meiszp    时间: 2016-9-29 23:16

回复 26# pcl_test

多谢大神,数据已经上传了,前面是有空格的,但21楼和26楼代码完美解决,26楼的更简洁。
还想好奇的问问,如果每列除的数相同,是不是还可以简单些?
作者: meiszp    时间: 2016-9-29 23:19

回复 28# WHY

谢谢!您的代码似乎也对文件数据做了修改,但看不懂,如果想更改除数,不知道怎么做。
作者: pcl_test    时间: 2016-9-29 23:38

本帖最后由 pcl_test 于 2016-9-29 23:39 编辑

回复 31# meiszp
26楼
  1. powershell -c "dir *.txt|?{$_ -is [IO.FileInfo]}|%%{gc $_|%%{if($_ -match '^\s*$'){$_}else{$a=($_.trim() -split '\s+');$line='';for($i=0;$i -le ($a.length-1);$i++){$line+='  '+('{0:e8}' -f ($a[$i]/指定的共同除数))};$line.trim()}}|out-file ('New_'+$_.name) -encoding ascii}"
  2. pause
复制代码
28楼($b.Value/++$i)改为($b.Value/指定的共同除数)
作者: codegay    时间: 2016-9-30 09:01

python 的pandas 处理起来真的是完全不费力啊。

pandas 是一个python用来进行数据处理和计算的库,提供了很多非常简单友好易用的数据处理相关的接口.

处理单个文件的代码示例:
  1. #2016年9月30日 08:39:27 codegay
  2. from pandas import *
  3. csv = read_csv("F31_03.txt",sep='\s+',header=None)
  4. s = Series([10,20,30,40,50,60,70])
  5. newcsv = csv / s #csv 中的数据每列除以 s中对应的数值
  6. print(newcsv)
复制代码

作者: WHY    时间: 2016-10-10 22:17

发现win8.1(PowerShell 4.0)与 win7(PowerShell 2.0)在脚本块中定义变量有区别
脚本块中的变量作用域原本应该是Local性质的,但win7把它当作Global传递,混乱了。

以下代码win7、win8.1测试通过(第1列/10;第2列/20;第3列/30;......):
  1. @echo off
  2. set "r='\d+\.?\d*[Ee][-+]\d{3}'"
  3. set "s=[IO.File]::ReadAllText($_,[Text.Encoding]::Default)"
  4. md new\ 2>nul
  5. PowerShell -c "dir *.txt|%%{[regex]::Replace(%s%,\"[^^`r`n]+\",{param($a,$global:i=0);[regex]::Replace($a.Value,%r%,{param($b);($b.Value/++$global:i/10).ToString('e8')})})>('new\'+$_.Name)}"
  6. pause
复制代码





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