Board logo

标题: [文本处理] [已解决]批处理如何对含科学计数数字的txt批量修改? [打印本页]

作者: alexwxcong    时间: 2010-5-1 20:54     标题: [已解决]批处理如何对含科学计数数字的txt批量修改?

我有如下内容的大量txt文件
2.0000000000000001e-001
0.0000000000000000e+000
0.0000000000000000e+000
-2.0000000000000001e-001
1.6695009999999998e+005
2.8049900000000001e+004
需要对科学计数改为正常数字,即如下
0.2
0
0
-0.2
166950.09999999998
28049.900000000001

[ 本帖最后由 alexwxcong 于 2010-5-2 20:30 编辑 ]
作者: alexwxcong    时间: 2010-5-1 20:56

诚请高手帮忙,俺琢磨了一天了,实在水平太低
作者: cjiabing    时间: 2010-5-1 21:34

不懂数学,哈哈,不懂科学计数!~不过应该不难,只是麻烦点
作者: alexwxcong    时间: 2010-5-1 21:43

e-001就是前面的2.0000000000000001乘以0.1
e+000数字不变
e+005就是前面的1.6695009999999998乘以100000
e+004就是前面的2.8049900000000001乘以10000
作者: yangfengoo    时间: 2010-5-1 23:26

关键是P难以处理小数
作者: hanyeguxing    时间: 2010-5-1 23:26

1,“大量txt文件”是否指多个txt文本?
2,“含科学计数数字”,那么文本中是否还含有其他内容?
如果有,区分规则是什么?
3,“含科学计数数字”的构成规则是什么?
-2.0000000000000001e-001都是这样的模式?
作者: sgaizxt001    时间: 2010-5-2 00:36

我的漏洞好多,编辑掉。看看我师傅的代码先

[ 本帖最后由 sgaizxt001 于 2010-5-2 04:26 编辑 ]
作者: namejm    时间: 2010-5-2 01:54

  1、小数点后的位数是否只保留有16位?
  2、是否所有的正数都没有前缀+而只有负数才有前缀-?
  4、e后的004、005之类的是否有可能会达到999?请给出它的范围。
作者: hanyeguxing    时间: 2010-5-2 03:11

1,代码没有优化,所以速度。。。100行转换实测耗时2.46妙,汗一个先
2,要求所有文本内只存在科学记数的内容,不含其他内容。
3,批处理放在同一目录下,新生成的文本将放到test子目录中。
4,e后的数字允许范围为000到999
5,小数部分最多保留16位(按楼主的要求)
6,数字小于0.0000000000000001时将被近似为0.0000000000000001
  1. @echo off&setlocal enabledelayedexpansion
  2. if not exist "test\" md test
  3. for %%z in (*.txt) do (
  4. for /f "usebackq tokens=1,2* delims=e." %%a in ("%%z") do (
  5. set a=%%a&set b=%%b&set c=%%c
  6. set d=!c:~1!
  7. for %%d in (0 0) do if !d:~0^,1!==0 set d=!d:~1!
  8. if !a:~0^,1!==- set n=-&set a=!a:~1!
  9. if !a:~0^,1!==0 (echo.0) else (
  10. set m=!a!!b!
  11. if !c:~0^,1!==+ (
  12. if !d! lss 16 (
  13. set/a d+=1
  14. for %%d in (!d!) do set m=!m:~0,%%d!.!m:~%%d!
  15. ) else (
  16. set/a a=d-16
  17. for /l %%d in (1,1,!a!) do set z=!z!0
  18. set m=!m!!z!
  19. )
  20. ) else (
  21. set/a a=d-1
  22. for /l %%d in (1,1,!a!) do set z=!z!0
  23. set m=0.!z!!m!&set m=!m:~0,18!
  24. )
  25. echo.!m!|find ".">nul 2>nul&&call:f !m!
  26. echo.!n!!m!
  27. )
  28. set n=&set z=))>test\%%z
  29. exit
  30. :f
  31. set f=%1
  32. if %f%==0.0000000000000000 set f=0.0000000000000001
  33. for /f "tokens=1,2 delims=." %%a in ("%f%") do set a=%%a&set b=.%%b
  34. :g
  35. if not "!b:~%g%,1!"=="" set/a g+=1&goto:g
  36. for /l %%a in (1,1,%g%) do if not !b:~-%%a^,1!==0 (
  37. set/a h=%%a-1
  38. if not !h!==0 for %%b in (!h!) do set "b=!b:~0,-%%b!"
  39. goto:e)
  40. :e
  41. set m=%a%%b%&set g=
  42. if %m:~-1%==. set m=%m:~0,-1%
复制代码

[ 本帖最后由 hanyeguxing 于 2010-5-2 03:37 编辑 ]
作者: namejm    时间: 2010-5-2 03:35

  大致的思路应当是这样的:
  把数值的正负号、整数部分、分数部分、指数部分和指数的正负号分别保存为变量,然后,把指定长度的纯0字符串拼接起来,拼接的规律为:若指数符号为负,则把纯0字符串放到整数部分之前;若指数符号为正,则把纯0字符串放到小数部分之后。把纯0字符串拼接之后,再根据指数部分把小数点位置做相应的移动,最后,把所有部分拼接起来,去掉整数部分之前和小数部分之后的纯0字符串即可。

  虽然思路比较简单,但是我居然发现在for语句中使用如下代码的时候出错了,如果把其中截取字符串的负号去掉,则该语句正常,百思不得其解:
  1. set num=!str_int:~0,-%num_point%!.!str_int:~%num_point%!!dec!
复制代码
  9楼的代码之所以慢,是因为使用了管道符号,频繁的I/O操作势必会拖慢速度。
作者: hanyeguxing    时间: 2010-5-2 03:44

1,本批处理使用%%~fd扩展删除0,所以批处理所在路径中最好别用敏感字符
2,本批处理直接修改原文件,所以运行前推荐先将所有原文件备份分:
  1. @echo off
  2. for %%z in (*.txt) do (
  3.       (for /f "usebackq tokens=1,2* delims=e." %%a in ("%%z") do (
  4.             setlocal enabledelayedexpansion
  5.             set a=%%a&set b=%%b&set c=%%c&set d=!c:~1!
  6.             for %%d in (0 0) do if !d:~0^,1!==0 set d=!d:~1!
  7.             if !a:~0^,1!==- set n=-&set a=!a:~1!
  8.             if !a:~0^,1!==0 (echo.0) else (
  9.             set m=!a!!b!
  10.             if !c:~0^,1!==+ (
  11.             if !d! lss 16 (set/a d+=1&for %%d in (!d!) do set m=!m:~0,%%d!.!m:~%%d!) else (
  12.             set/a a=d-16&for /l %%d in (1,1,!a!) do set z=!z!0
  13.             set m=!m!!z!
  14.             )
  15.             ) else (
  16.             set/a a=d-1&for /l %%d in (1,1,!a!) do set z=!z!0
  17.             set m=0.!z!!m!&set m=!m:~0,18!
  18.             if !m!==0.0000000000000000 set m=0.0000000000000001
  19.             )
  20.             if not "!m:.=!"=="!m!" set "m=!m:0= !"&for /f "delims=" %%d in ("!m!") do set m=%%~fd&set "m=!m:%cd%\=!"&set "m=!m: =0!"
  21.             echo.!n!!m!)
  22.       endlocal))>"%%z_"
  23.       del /q "%%z"
  24.       ren "%%z_" "%%z"
  25. )
复制代码
至于:
原帖由 namejm 于 2010-5-2 03:35 发表
虽然思路比较简单,但是我居然发现在for语句中使用如下代码的时候出错了,如果把其中截取字符串的负号去掉,则该语句正常,百思不得其解:
代码:set num=!str_int:~0,-%num_point%!.!str_int:~%num_point%!!dec!

因为没有看到完整代码,个人猜测是这个原因:http://bbs.bathome.net/thread-7629-4-1.html的46楼

[ 本帖最后由 hanyeguxing 于 2010-5-2 09:02 编辑 ]
作者: alexwxcong    时间: 2010-5-2 11:16

谢谢hanyeguxing ,我先备份一个试过了,按你的方法好像是可以,谢谢啊
作者: alexwxcong    时间: 2010-5-2 11:19

原帖由 namejm 于 2010-5-2 01:54 发表
  1、小数点后的位数是否只保留有16位?
  2、是否所有的正数都没有前缀+而只有负数才有前缀-?
  4、e后的004、005之类的是否有可能会达到999?请给出它的范围。



1,小数点后的位数可以不用太多,8位就够了
2,前缀可以不用考虑,可以直接删除E前的那个数字
3,E后面的004/005这种不会超过010
作者: terse    时间: 2010-5-2 11:25

004/005 是否根据+-确定小数点前移或后移4位或5位?如是这样可否移动这个点呢
作者: alexwxcong    时间: 2010-5-2 11:32

恩,其实科学计数就是移动小数点
作者: 随风    时间: 2010-5-2 12:35

虽然思路比较简单,但是我居然发现在for语句中使用如下代码的时候出错了,如果把其中截取字符串的负号去掉,则该语句正常,百思不得其解:

能给出出错部分的完整代码吗
作者: CUer    时间: 2010-5-2 13:20

精度比较低
  1. @echo off
  2. for /f %%a in (a.txt) do (
  3.     math.exe %%a
  4. )
复制代码

作者: 随风    时间: 2010-5-2 13:25

不知道对不对
:
  1. @echo off & setlocal enabledelayedexpansion
  2. for /f "tokens=1,2 delims=e" %%i in (a.txt) do (
  3.    set var=%%j
  4.    for /f "tokens=1,2 delims=." %%a in ("%%i") do (
  5.       set z=%%a&set x=%%b00000000000000000
  6.     )
  7.     set f=&set h=
  8.     if "!var:~0,1!"=="-" set f=a
  9.     set var=!var:~1!
  10.     for /f "tokens=* delims=0" %%a in ("!var!") do (
  11.        if "!f!"=="" (set z=!z!!x:~0,%%a!&set x=!x:~%%a!) else (
  12.           if "!z:~0,1!"=="-" set z=!z:-=!&set h=-
  13.           set z=0000000000000000000!z!
  14.           set x=!z:~-%%a!!x!
  15.           set z=!z:~0,-%%a!
  16.           for /f "tokens=* delims=0" %%c in ("!z!") do (
  17.              if "%%c"=="" set z=0
  18.            )
  19.        )
  20.     )
  21.     echo !h!!z!.!x:~0,8!
  22. )
  23. pause
复制代码

作者: CUer    时间: 2010-5-2 13:47

精度非常接近了
  1. gawk "{printf(\"%.12f\n\",$0)}" a.txt | gawk "{gsub(/0+$/,\"\");gsub(/\.$/,\"\")}1"
复制代码

作者: alexwxcong    时间: 2010-5-2 14:48

原帖由 alexwxcong 于 2010-5-2 11:16 发表
谢谢hanyeguxing ,我先备份一个试过了,按你的方法好像是可以,谢谢啊

不好意思啊,发现一个问题,就是我这种txt文件大概有3千多个,其中差不多1000左右是正常的,没有科学计数的,如果按照hanyeguxing兄这个代码执行,会将其中原本正常的变成这样
0
0
0
0
0.829499998926702
0.3405
原本是这样的
0.2
0
0
-0.2
82949.9998926702
34050
作者: alexwxcong    时间: 2010-5-2 16:20

原帖由 随风 于 2010-5-2 13:25 发表
不知道对不对
echo off & setlocal enabledelayedexpansion
for /f "tokens=1,2 delims=e" %%i in (a.txt) do (
   set var=%%j
   for /f "tokens=1,2 delims=." %%a in ("%%i") do (
      set z=%%a&set x ...

我的不是在一个txt里面,是有数千个txt
作者: namejm    时间: 2010-5-2 17:03

  用10楼的思路,得到如下代码(仅处理一个文件):
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. set str_zero=
  4. for /l %%i in (1,1,10) do set str_zero=0!str_zero!
  5. for /f "tokens=1-3 delims=.e" %%i in (test.txt) do (
  6.     set int=%%i
  7.     set char_int=
  8.     if "!int:~0,1!"=="-" (
  9.         set char_int=-
  10.         set int=!int:~1!
  11.     )
  12.     set dec=%%j
  13.     set e=%%k
  14.     set char_e=!e:~0,1!
  15.     set e=!e:~1!
  16.     call :cut_zero_left !e!
  17.     if "!char_e!"=="+" (
  18.         set str_dec=!dec!%str_zero%
  19.         call set num=!int!%%str_dec:~0,!num_NoLeftZero!%%.%%str_dec:~!num_NoLeftZero!%%
  20.     ) else (
  21.         set str_int=%str_zero%!int!
  22.         call set num=%%str_int:~0,-!num_NoLeftZero!%%.%%str_int:~-!num_NoLeftZero!%%!dec!
  23.     )
  24.     for /f "tokens=1* delims=." %%x in ("!num!") do (
  25.         if "!char_e!"=="-" (
  26.             call :cut_zero_left %%x
  27.             set num_NoRightZero=%%y
  28.         )
  29.         if "!char_e!"=="+" (
  30.             call :cut_zero_right %%y
  31.             set num_NoLeftZero=%%x
  32.         )
  33.     )
  34.     if defined num_NoRightZero (
  35.         echo !char_int!!num_NoLeftZero!.!num_NoRightZero!
  36.     ) else echo !char_int!!num_NoLeftZero!
  37. )
  38. pause
  39. exit
  40. :cut_zero_left
  41. :: 去除字符串最左侧的纯0字符串
  42. set num_NoLeftZero=0
  43. for /f "tokens=1* delims=0" %%i in ("%1") do set num_NoLeftZero=%%i
  44. goto :eof
  45. :cut_zero_right
  46. :: 去除字符串最右侧的纯0字符串
  47. set num_NoRightZero=%1
  48. :loop
  49. if "%num_NoRightZero:~-1%"=="0" (
  50.     set num_NoRightZero=!num_NoRightZero:~0,-1!
  51.     if defined num_NoRightZero goto loop
  52. )
  53. goto :eof
复制代码

  经测试,100行数据耗时约1.5秒,测试环境为:1.6GHZ主频、512M内存、XP_SP3系统。

  若楼主觉得处理结果完全符合你的需要,我将改写代码,以适应成百上千个txt文档的情况;若有其他需求,请继续提出。

  10楼提到的那个问题,是因为没有使用 call 来延迟变量的扩展导致的,和字符串截取长度超过字符串本身长度无关。
作者: namejm    时间: 2010-5-2 17:07

原帖由 alexwxcong 于 2010-5-2 14:48 发表
不好意思啊,发现一个问题,就是我这种txt文件大概有3千多个,其中差不多1000左右是正常的,没有科学计数的

  到底是某些文本中科学计数和常规计数混杂的,还是每个文档要么全是科学计数要么是常规计数?请说明白一点。

  到目前为止,跟帖已经达到两页,请楼主把所有的需求全部更新到顶楼,否则,别人要准确全面地了解你的本意,还得从头到尾全部看一遍帖子,其间思路一变再变,恐怕没几个人有耐心把你帮到底。
作者: alexwxcong    时间: 2010-5-2 17:52

哦,谢谢,是这样的,每个txt内容只有上面贴出的6行,txt文件的数量大概是3千多,
目的是,把全部的txt转换成标准的常规数字
现状是两种txt都有,有些是常规数字,有些是科学计数法,不存在一个txt里面既有常规数字又有科学计数法的情形
思路没变,只不过没表述清楚

[ 本帖最后由 alexwxcong 于 2010-5-2 17:54 编辑 ]
作者: 随风    时间: 2010-5-2 18:28

似乎楼主没看见23楼的帖子的最后两行,又或是认为那与他无关,只要不是解决我问题的字我坚决不看 ^_^
也怀疑楼主有没有测试18楼的代码。
作者: namejm    时间: 2010-5-2 18:38

  哈哈,还是随风18楼的思路简洁,速度更快,可惜楼主一直没有把已知条件交代精确,老是想兼容各种特殊情况,反倒搞复杂了。

  我估计楼主在截取小数点后8位之后,可能还会要求四舍五入、去掉最后的纯0字符串之类的,唉,亲爱的楼主,你这样像挤牙膏一样一次来一点,何时是个尽头啊?
作者: netbenton    时间: 2010-5-2 19:16

有点不明白,楼主一楼的例子,为什么第一行和最后一行的后面都有一个1,但是结果只有最后一行保留了这个1,是根据什么呢?

我也来个,这里你看不到if
  1. @echo off&setlocal enabledelayedexpansion
  2. set file=aaa.txt
  3. for /f "delims=.e tokens=1-4" %%a in (%file%) do (
  4.         for /f "delims=0 tokens=1*" %%x in ("%%c") do (
  5.                 set/a dot=%%y+0
  6.                 set -=0000000000%%a
  7.                 set +=%%b
  8.                 for /f "tokens=1,2" %%1 in ("%%x !dot!") do (
  9.                         set %%1=!%%1:~,%%1%%2!.!%%1:~%%1%%2!
  10.                 )
  11.                 for /f "tokens=*" %%o in ("!-:0= !!+:0= !") do (
  12.                         set str=-%%~nxo.
  13.                         set str=!str:-.=-0.!
  14.                         set str=!str: =0!
  15.                         echo;结果:!str:~1,-1!
  16.                 )
  17.         )
  18. )
  19. pause
复制代码

[ 本帖最后由 netbenton 于 2010-5-2 19:25 编辑 ]
作者: alexwxcong    时间: 2010-5-2 20:21

因为我开始没完全说清楚,让各位费解了,实在对不住,在此表示歉意,我已经另行找了一个搜索所有科学计数法的txt,另存到一个文件夹,在用hanyeguxing兄的方法就可以解决了,在这谢谢了,特此结贴。
作者: hanyeguxing    时间: 2010-5-2 20:31

根据楼主要求:
1,移位数字范围为000到015
2,允许科学记数与普通数字(非16进制)混排
3,100行测试,运行时间小于0.08秒
4,所有科学记数转换的数字只精确到小数8位(未使用4舍5入)
5,对于小于0.00000001的数字,精确到0.00000001
  1. @echo off
  2. for %%a in (*.txt) do (
  3. (for /f "usebackq delims=" %%b in ("%%a") do (
  4.       setlocal enabledelayedexpansion
  5.       set b=%%b
  6.       if !b:~18^,1!==e set a==
  7.       if !b:~19^,1!==e set a==
  8.       if not defined a (echo.%%b) else (
  9.             for /f "tokens=1,2* delims=e." %%c in ("%%b") do (
  10.                   set c=%%c&set d=%%d&set e=%%e&set f=!e:~2!
  11.                   if !f:~0^,1!==0 set f=!f:~1!
  12.                   if !c:~0^,1!==- set g=-&set c=!c:~1!
  13.                   if !c:~0^,1!==0 (echo.0) else (
  14.                   set h=!c!!d!
  15.                   if !e:~0^,1!==+ (
  16.                   set/a f+=1&for %%f in (!f!) do set h=!h:~0,%%f!.!h:~%%f!
  17.                   ) else (
  18.                   set/a f-=1&for /l %%f in (1,1,!f!) do set i=!i!0
  19.                   set h=0.!i!!h!
  20.                   )
  21.                   for /f "tokens=1* delims=." %%f in ("!h!") do set f=%%g&set h=%%f.!f:~0,8!
  22.                   if !h!==0.00000000 set h=0.00000001
  23.                   if not "!h:.=!"=="!h!" set "h=!h:0= !"&set "h=!h:.=#!"&for /f "delims=" %%f in ("!h!") do set h=%%~ff&set "h=!h:%cd%\=!"&set "h=!h:#=.!"&set "h=!h: =0!"
  24.                   if !h:~-1!==. set h=!h:~0,-1!
  25.             echo.!g!!h!)))
  26.       endlocal))>"%%a_"
  27. del /q "%%a"
  28. ren "%%a_" "%%a")
复制代码
结贴时,请修改主题并在前面加[已解决]

[ 本帖最后由 hanyeguxing 于 2010-5-2 20:36 编辑 ]
作者: terse    时间: 2010-5-3 15:00

  1. @echo off&setlocal enabledelayedexpansion
  2. set "l=0000000000"
  3. for /f "tokens=1,2 delims=e" %%i in (a.txt) do (
  4.     set "str=%%i"
  5.     if "%%j" neq "" (
  6.     set /a "i=%%j%%1000"
  7.     if !i! neq 0 (
  8.     if !i! lss 0 (
  9.     for /f "tokens=1,2 delims=." %%a in ("%%i") do (
  10.         set "str=%%a"
  11.         if %%a lss 0 (set j=-0.)else set "j=0."
  12.         set "str=%l%!str:-=!"
  13.         set "b=%%b"
  14.         for %%c in (!i!) do set "str=!j!!str:~%%c!!b:~,%%c!"
  15.         )
  16.         ) else (
  17.           for /f "tokens=1,2 delims=." %%a in ("%%i") do (
  18.               set "str=%%b"
  19.               for %%c in (!i!) do set "str=%%a!str:~,%%c!.!str:~%%c!"
  20.         )
  21.       )
  22.     )
  23.   )
  24.           if "!str:0=!" neq "." (echo !str!)else echo 0
  25. )
  26. pause
复制代码





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