Board logo

标题: [文本处理] 批处理如何给数字添加千分位分隔符? [打印本页]

作者: zhangenming    时间: 2016-3-8 18:03     标题: 批处理如何给数字添加千分位分隔符?

数据位数不定0~7位
正负不定
怎么每隔三位以","号分割输出


是纯数字
试了好多办法
都不完美
比如除法运算
或者%value:~-6,3%这样的
作者: zhangenming    时间: 2016-3-8 18:04

别看我注册时间
初中注册的
现在大学狗
作者: ivor    时间: 2016-3-8 18:30

回复 1# zhangenming
  1. set a=123456
  2. if [%a:~3,3%] equ [] (echo %a:~0,3%) else if [%a:~6,3%] equ [] (echo %a:~0,3%,%a:~3,3%) else (echo %a:~0,3%,%a:~3,3%,%a:~6,3%)
复制代码

作者: WHY    时间: 2016-3-8 19:44

  1. set "Num=1234567"
  2. PowerShell -c "(%Num%).ToString('0,0')"
复制代码

作者: sishentibu    时间: 2016-3-8 20:08

我是老老实实的算的。。a为变量。。
  1. @echo off
  2. set a=-2000000
  3. set /a b=a/1000
  4. set /a c=a/1000000
  5. if %b%==0 (echo %a%) else (
  6. if %c%==0 (echo %a:~0,-3%,%a:~-3%) else (echo %a:~0,-6%,%a:~-3,3%,%a:~-3%))
复制代码

作者: CrLf    时间: 2016-3-8 21:11

正则正向预查:
  1. @mshta http://bathome.net/s/hta/ "'%random%'.replace(/\d(?=(?:\d{3})+$)/g,'$&,')"|more
复制代码

作者: codegay    时间: 2016-3-8 22:41

楼主可以专心学一门语言了。
作者: WHY    时间: 2016-3-8 23:12

.net 正则中有一个从右向左搜索的选项:
  1. [regex]::Replace('1234567','(?<=\d)\d{3}', ',$&','RightToLeft')
复制代码

作者: happy886rr    时间: 2016-3-9 01:19

回复 5# sishentibu


  我发现1000052是个7位数,但是不兼容
作者: happy886rr    时间: 2016-3-9 01:23

回复 2# zhangenming
批处理也能完成这个任务,只是绕点,但是也完成了。兼容正负数,可以无限位数,也可以切割任意长度字符串。
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. set num=-14159265358979323846264338327950288314159265358979323846264338327950288
  4. :cut
  5. set p=!num:~-3!
  6. if "!num!"=="" (echo !p1:~0,-1! & pause & exit)
  7. set p1=!p!,!p1!
  8. set num=!num:~0,-3!
  9. goto cut
复制代码
最大可以切割5千多位的超级大数
运行实例
作者: 依山居    时间: 2016-3-9 02:21

python可以这样:
  1. "{:,}".format(33333)
复制代码

作者: CrLf    时间: 2016-3-9 02:49

突然觉得批处理之家已然成为各种脚本一锅乱炖的大杂烩...
作者: codegay    时间: 2016-3-9 02:59

回复 12# CrLf


    提问的人估计超级不爽。
作者: caruko    时间: 2016-3-9 09:21

回复 3# ivor


    直接判断 >=1000  AND >= 1000000 不就行了
作者: codegay    时间: 2016-3-9 10:43

本帖最后由 codegay 于 2016-3-9 12:17 编辑

哈哈,又撸了个python代码,处理全是数字应该没问题。
  1. 这个问题只要把判断并去掉正负号,然后把字符串翻转,这个问题就等于如何把一个字符串或者序列每3个切成一份。
  2. >>> s="12345"
  3. >>> ','.join([s[::-1][r:r+3] for r in range(0,len(s),3)])[::-1]
  4. '12,345'
  5. >>>
复制代码

作者: happy886rr    时间: 2016-3-9 11:11

回复 15# codegay

呵呵,就跟切菜一样。
作者: sishentibu    时间: 2016-3-9 11:48

本帖最后由 sishentibu 于 2016-3-9 11:52 编辑

回复 9# happy886rr

有个地方写错了。
  1.     @echo off
  2.     set a=1000052
  3.     set /a b=a/1000
  4.     set /a c=a/1000000
  5.     if %b%==0 (echo %a%) else (
  6.             if %c%==0 (echo %a:~0,-3%,%a:~-3%) else (echo %a:~0,-6%,%a:~-6,3%,%a:~-3%))
复制代码
最后一个echo改下就好了
作者: WHY    时间: 2016-3-9 22:47

本帖最后由 WHY 于 2016-3-10 21:19 编辑
  1. @echo off & setlocal enabledelayedexpansion
  2. set "n=-1234567890"
  3. for /l %%i in (-18 3 -3) do set "n=!n:~0,%%i!,!n:~%%i!"
  4. for /f "tokens=*delims=," %%i in ("%n%") do set "n=%%i"
  5. echo;%n:-,=-%
  6. pause
复制代码

作者: sishentibu    时间: 2016-3-10 20:39

本帖最后由 sishentibu 于 2016-3-10 20:56 编辑

回复 18# happy886rr


抱歉,开始想错了。

set num=!num:~0,-3!
如果num只有2位数,是不是num就为空了?就是"!num!"=="" ?
作者: happy886rr    时间: 2016-3-10 21:36

回复 20# sishentibu
对,0,-3那句就是去掉最后三个。自然就空了。
作者: sishentibu    时间: 2016-3-11 19:27

回复 21# happy886rr

你那割法是真巧妙,按我那写法,位数一多就抗不住了。
想了下,你这种写法,只要是有规律的分割都可以啊,不仅仅是数字
作者: happy886rr    时间: 2016-3-11 19:50

本帖最后由 happy886rr 于 2016-3-11 20:20 编辑

回复 22# sishentibu
基本上就是按字符串分割的,所以会出现负号被分割的情况如-,300
还需要加一句!p1:-,=-!就更完美了。
这是改进后的
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. set /p num=输入数字:
  4. :cut
  5. if "!num!"=="" (
  6. set p1=!p1:-,^=-!
  7. echo !p1:~1! &pause>nul&exit
  8. )
  9. set p1=,!num:~-3!!p1!
  10. set num=!num:~0,-3!
  11. goto cut
复制代码

作者: sishentibu    时间: 2016-3-11 20:54

回复 22# happy886rr

我又有疑问了。。
第一遍执行的时候,set p1=,!num:~-3!!p1! ,p1不是还没有定义吗,难道后方的那个p1直接为空?
上面的还能解释的话,set p1=!p1:-,^=-! 就有些不太明白了。一般情况下,不是!p1:-,=-! 吗?为什么会多了个^,这个不是转义用的吗?
我去掉^的情况下,批处理还是正常运行了。。然后按我的理解,!p1:-,^=-!不是语法不对吗。。。
作者: happy886rr    时间: 2016-3-11 21:57

本帖最后由 happy886rr 于 2016-3-11 22:03 编辑

回复 23# sishentibu
因为setlocal开启变量延迟,所以p1不用定义。直接拿来用。
set p1=!p1:-,^=-! 一行里出现两个等号,怕歧义,所以加个^让机器好理解
作者: sishentibu    时间: 2016-3-12 19:48

回复 24# happy886rr
Set str=%str=-% 类似这种,不是set的本来用法吗,你这种写法我反而没看懂。。
也就是说,从结果来说,加不加^都可以的吧?
作者: happy886rr    时间: 2016-3-12 19:54

回复 25# sishentibu
有时候会有用比如你要过滤等号!str:=-=!就会歧义
作者: sishentibu    时间: 2016-3-13 18:02

回复 26# happy886rr

好吧。
那是不是加了^, 就是我们所需要的那个赋值符号?
但一般来说,用^转义了后,不是普通的一个字符吗
作者: happy886rr    时间: 2016-3-13 18:46

回复 27# sishentibu
这好像就是个漏洞,不管转不转义,!str: ==!,里边只要遇到第一个等号就工作。微软就这么设计的。
作者: CrLf    时间: 2016-3-13 22:53

回复 28# happy886rr


    不会有歧义的,过滤等号和*一直是个老大难问题(摊手)...详见:
http://www.bathome.net/viewthread.php?tid=6038
作者: sishentibu    时间: 2016-3-14 17:46

回复 28# happy886rr


    29#的CrLf貌似提出异议了。不过我看的有点晕,暂时不去研究那个了
关于截断,我还有个问题请教下
例如
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. for /f %%i in ("123465") do (
  4. echo %%i
  5. set a=%%i
  6. echo !a:~0,2!)
  7. pause
复制代码
这个可以不可以没有set a=%%i 这一步的?我自己试不出来。
作者: happy886rr    时间: 2016-3-14 19:20

回复 30# sishentibu
set a=%%i这个必须有。
我发现for和if比goto运行的速度快很多,所以我那个分割可以写成for的,速度简直快了几十倍,还有批处理居然按行读取硬盘的bat文件,因此我把for循环弄成一行,让机器一次读完一个for语句。我设置为1000次循环,即最大3000位数字截取,运行速度快的惊人。
  1. @echo off&setlocal enabledelayedexpansion
  2. set /p num=输入数字:
  3. for /l %%i in (1 1 1000) do (if !num! equ 0 (set p1=!p1:-,=-!&set /p =!p1:~1!) else (set p1=,!num:~-3!!p1!&set num=!num:~0,-3!))
复制代码
另外我发现用for /l这个可以加快计算圆周率和开平方的速度.
作者: sishentibu    时间: 2016-3-14 19:32

回复 31# happy886rr


    你研究的可够多的
批处理按行处理,这个我在论坛的基础教程里面有看到过的。
而且,我现在处理的东西都比较小,所以对于效率这块不是很注意。虽然我看到很多说goto的效率低,但我个人感觉,写成goto的形式,对于分类处理的东西更好写。。
另外,批处理有没有类似按行运行的办法的?因为我不是很熟悉,经常要把批处理改很多次才能达到最终要求。试过加pause,但行数一多就感觉好麻烦。而且有时碰到一闪而过的,更不好判断哪里的问题了
作者: happy886rr    时间: 2016-3-14 19:46

回复 32# sishentibu
这个好办。用token findstr /n,截取bat文件。然后将行号和pause都echo到bat文件的每一行下,就是你写个批处理给你要测试的bat添加pause和行号,方便你查错。
作者: sishentibu    时间: 2016-3-14 20:58

回复 33# happy886rr
没懂。。可以帮我举个例子吗,就用楼上你写的代码

刚才写的时候又碰到个问题。关于时间的处理的。
手动设置t1,t2时间,然后用下面代码是可以的
  1. set /a t=(%t2:~0,2%-%t1:~0,2%)*60+(%t2:~3,2%-%t1:~3,2%)
复制代码
但我在for /f 语句中,读取到时间,对时间进行计算就变成一闪而过了,这个哪里有问题?
  1. set /a t=(!t2:~0,2!-!t1:~0,2!)*60+(!t2:~3,2!-!t1:~3,2!)
复制代码

作者: happy886rr    时间: 2016-3-14 21:24

回复 34# sishentibu
批处理遇到0开头的就当八进制处理了,遇到0x开头的就16进制计算了,计算时间差这块需要加个100就行了,然后截取。
作者: CrLf    时间: 2016-3-14 21:30

回复 35# happy886rr


    不用截取,两部分抵消了
作者: happy886rr    时间: 2016-3-14 22:51

回复 36# CrLf
是set/a 1!t2:~3,2!-1!t1:~3,2!,加前缀1?
另外我看到大师 2013年的 关于批处理计算圆周率的三个方案.我发现了一个收敛速度快1000倍的公式,这样就实现了计算圆周率的模块化。可以直接计算第n位,
pi=2*1+2*1!/3!!+2*2!/5!!+2*3!/7!!+...+2*k!/(2*k+1)!!+...这个公式的收敛速度只有2,而且分母不是2。需要分母是2的次幂的公式,这样除以2的次幂就相当于移位>>
作者: CrLf    时间: 2016-3-15 00:15

回复 37# happy886rr


    不了解,好像没见过符合条件的公式
作者: CrLf    时间: 2016-3-15 02:18

回复 34# sishentibu


    在 for 里要注意对反括号进行转义,否则容易造成语法错误
作者: sishentibu    时间: 2016-3-15 11:50

回复 35# happy886rr


    这个我倒是没注意,我晚上加1试试
不过有2个问题,我看CrLf 貌似有不同意见
还有,我自己在win7下试过,貌似截取出来的是“ 8:30" 类似的,而不是”08:30“,就是直接为空的,而不是0

另外,那个给批处理加暂停的那个解释我没看懂啊
作者: sishentibu    时间: 2016-3-15 12:03

回复 39# CrLf


    反括号指的是 ) ?
刚才查了下,貌似是说,第一个)会去跟 do ( 这个括号配对去了。
对于进行转义,我还是有点疑惑。
转义的意思,不是把特殊作用的字符,转换成普通显示的字符吗?
但我实际中,是需要它在for内部跟前一个(配对。如果把)转义成普通字符了,那这个)还会跟前一个(配对?
如果语句写的比较复杂,括号套括号的时候,是不是同样也有这个问题?如果有三层,四层括号,按这个逻辑,貌似就算加了转义,里面的配对情况依然会乱吧?
作者: happy886rr    时间: 2016-3-15 12:35

回复 40# sishentibu
你写的(!t2:~3,2!-!t1:~3,2!)就是在截取分钟,万一是8点09分,你试试看批处理会不会疯掉。第二个问题另外做个批处理给要调试的批处理每行下添加pause和行号,方便你知道运行到第几行。
作者: happy886rr    时间: 2016-3-15 13:01

本帖最后由 happy886rr 于 2016-3-15 15:09 编辑

回复 38# CrLf
这个算法收敛很快,4次循环就可得到8位有效派值,遇到的问题主要是浮点运算,我的核心算法是
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. set t=100000000
  4. set /a pi=t-t/2-t/5-t/6
  5. for /l %%i in (1 1 4) do (set /a pi=((4*t/(8*%%i+1^)-2*t/(8*%%i+4^)-t/(8*%%i+5^)-t/(8*%%i+6^)^)^>^>4*%%i^)+pi)
  6. echo 3.!pi!
  7. pause
复制代码
在往后边循环,由于浮点运算的关系,我需要用bat模拟浮点运算,或者用快速模幂乘。后边的设计比较复杂,包括余项的处理。
作者: sishentibu    时间: 2016-3-16 23:17

回复 42# happy886rr

这两天头痛,懒的测试。我过几天在在虚拟机中改系统时间测试下

“第二个问题另外做个批处理给要调试的批处理每行下添加pause和行号,方便你知道运行到第几行。”,我明白你要表达的意思,但是我不会。。。
目前我就是for,set,echo,if 之类的用的多点,findstr之类的基本就没用过。。
作者: sishentibu    时间: 2016-3-17 12:34

回复 45# happy886rr


    我直接拿来测试了下,稍微有点问题。
  1. echo echo ----^>第!i!行
复制代码
这里的>貌似有点问题,有这个的时候,我处理后的批处理运行不了,去掉就好了(虽然我知道这个只是显示用的)

另外,你说的“处理另一个批处理时遇到!!或者%%号就扩展了”不的很清楚表达的意义,但实际情况确实是包含%%的批处理无法处理,直接一闪而过了。例如
  1. @echo off
  2. set /p=<nul >url.txt
  3. for /f %%i in (dnsserver.txt) do (
  4. echo %%i>>url.txt
  5. echo %%ipage/2/>>url.txt
  6. echo %%ipage/3/>>url.txt)
复制代码
看了处理结果后,我感觉是不是可以不用这么麻烦。因为序号是一行一个,for /f也是一次读取一行,那么直接计数不就好了吗,也就不用读取行号了。

对于这种方法,我简单的测试了下。对于正确的地方没的说。但是错误的地方,如果有括号的,如for之类的,是不是只要括号中的内容有误,就直接退出了?然后我就可以先检查这个语句?
作者: happy886rr    时间: 2016-3-17 12:54

回复 46# sishentibu
差不多就是逐行运行,停到哪有行号,再下一步闪退,就知道是第几行出错了。
作者: sishentibu    时间: 2016-3-17 17:30

回复 47# happy886rr


    我想了下,貌似出问题的,基本都会有%%,!!之类的。然后这类却不支持。。。
作者: happy886rr    时间: 2016-3-17 19:30

回复 47# sishentibu
我改进了方法,这回可以完美支持所有批处理了。批处理一键拖拽调试器,支持带有空格的任意特殊路径。任意字符串。
  1. @echo off
  2. if %1=="" exit
  3. set n=1
  4. (for /f "delims=" %%i in ('type %1') do (
  5. call,echo @echo ---第%%n%%行---
  6. set /a n+=1
  7. set /p =%%i<nul
  8. echo,&echo pause^>nul&echo,
  9. )
  10. )>.\正在调试_%~nx1
  11. start .\正在调试_%~nx1
复制代码

作者: WHY    时间: 2016-3-17 20:54

回复 48# happy886rr


    我不想打击你,用批处理拖拽,它这么弄都不能够算完美
作者: sishentibu    时间: 2016-3-17 23:06

回复 48# happy886rr

我测试了下,貌似还是存在问题。有2个方面。
第一个,还是我前面给过的那个批处理,文件名1 (2).cmd,直接就一闪而过了
  1. @echo off
  2. set /p=<nul >url.txt
  3. for /f %%i in (dnsserver.txt) do (
  4. echo %%i>>url.txt
  5. echo %%ipage/2/>>url.txt
  6. echo %%ipage/3/>>url.txt)
  7. pause
复制代码
第二个问题,用你的上一个解决方案,那个批处理本身是可以运行的。但是用这个批处理处理后,生成文件再运行,却出错了。

所以,我在想,是不是我们一开始的方向就有问题?

==================================================
关于这个批处理,我也有疑问
第二行,这个有用处?
第四行,为什么要用type命令呢?%1不是本身就表示拖过来的文件吗(虽然我自己试了,直接用1%有点问题)
第五行,call命令我查看了cmd的帮助,貌似没这种用法的解释?而且为什么n两边是2对%。。
第七行,set /p可以解决echo时候的%,!问题?这个我再测试下。
作者: happy886rr    时间: 2016-3-17 23:20

本帖最后由 happy886rr 于 2016-3-17 23:39 编辑

回复 50# sishentibu

你把文件名改改。1 (2).cmd这个名字既有空格又有小括号。批处理遇到有空格小括号的文件名,自然会出错。换个名字。




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