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

支持全角字符
awk -f format-table.awk data.txt
  1. function getWidth(str,LenStr,LenASC,LenHZ) {
  2. LenStr = length(str)
  3. LenASC = gsub( /[\x00-\x7F]/ , "" , str )
  4. LenHZ = length(str) / length("一")
  5. return  LenASC + LenHZ * 2
  6. }
  7. function getLengthHZ(str,LenHZ) {
  8. gsub( /[\x00-\x7F]/ , "" , str )
  9. LenHZ = length(str) / length("一")
  10. return  LenHZ
  11. }
  12. BEGIN {
  13. FS = " "
  14. while ( getline < ARGV[1] ) {
  15. for (i = 1; i <= NF; i++) {
  16. len = getWidth($i)
  17. if ( len > maxWidth[i] ) {
  18. maxWidth[i] = len
  19. }
  20. }
  21. }
  22. # print "--maxWidth--"
  23. # for ( i in maxWidth ) {
  24. # printf "%4s" , maxWidth[i]
  25. # }
  26. # printf "\r\n"
  27. # print "----"
  28. }
  29. {
  30. for (i = 1; i <= NF; i++) {
  31. LenHZ = getLengthHZ($i)
  32. printf "%-*s:" , maxWidth[i] + LenHZ , $i
  33. }
  34. printf "\r\n"
  35. }
复制代码
注意 第 35 行 由于 awk 环境不同,可能是 "+ LenHZ" 可能是 "- LenHZ"

TOP


用7楼获取全文最大字段长度的方法(中英文字符按存储字节数计算长度)可以进一步简化34楼所用计算方法中须区分中英文字符的步骤...
  1. @echo off &setlocal enabledelayedexpansion &set "maxZ=0"
  2. for /f "delims=" %%a in (1.txt) do for %%s in (%%a) do (
  3. set/p="%%s"<nul>"0.0"
  4. for %%b in (0.0) do if %%~zb gtr !maxZ! set "maxZ=%%~zb"
  5. )
  6. for /f "delims=" %%a in (1.txt) do (
  7. set "ss=" &for %%s in (%%a) do (
  8. set/p="%%s"<nul>"0.0" &for %%b in (0.0) do set/a "z=maxZ-%%~zb"
  9. set "_s="&for /l %%k in (1,1,!z!) do set "_s=!_s! "
  10. set "ss=!ss! %%s!_s!"
  11. )
  12. echo,!ss:~1!
  13. )
  14. del/q "0.0"&endlocal&pause&exit/b
复制代码

TOP

本帖最后由 aloha20200628 于 2024-7-21 14:08 编辑


关于中英文混合文本行的对齐输出最终取决于显示字体
已知的 ‘英文用一个字节,中文用2个字节’ 是指存储单位,而每个字符被物理显示到屏幕上的 ‘显示宽度’ 还是要看所选字体
选择中英文字符等宽字体可以简化算法步骤(因批处的字符串截取偏移量视同中英文字符偏移量=1),但显示观感会大打折扣
而选择中英文字符显示宽度成等分关系的字体(例如英文字符占1个显示宽度,中文字符占2个显示宽度,而cmd简中窗口的默认字体即为此型字体)须实时获取每个字段的显示宽度与 ‘全文最长字段’ 显示宽度的差距,此差距即所谓 ‘每个字段的空格填充量’,由此确保每行各列不等长字段能够对齐显示,据此原理调整了9楼代码如下,并已在cmd简中窗口中实测多种样本(最长混合字段可自定义,列数可自定义)均予顺利通过...
  1. @echo off &setlocal enabledelayedexpansion &set "maxZ=0"
  2. for /f "delims=" %%a in (1.txt) do for %%s in (%%a) do (
  3. set "s=%%s"&set "_len="&(call :_strLen)
  4. if !_len! gtr !maxZ! set "maxZ=!_len!"
  5. )
  6. for /f "delims=" %%a in (1.txt) do (
  7. set "ss=" &for %%s in (%%a) do (
  8. set "s=%%s"&set "_len="&(call :_strLen)
  9. set/a "z=maxZ-_len"&set "_s="&for /l %%k in (1,1,!z!) do set "_s=!_s! "
  10. set "ss=!ss! %%s!_s!"
  11. )
  12. echo,!ss:~1!
  13. )
  14. endlocal&pause&exit/b
  15. :_strLen //逐个字符计算》中文字符累加2,英文字符累加1。
  16.    if not defined s exit/b
  17.    if "!s:~0,1!" gtr "Z" (set/a "_len+=2") else (set/a "_len+=1")
  18.    set "s=!s:~1!" &goto :_strLen
复制代码

TOP

本帖最后由 newswan 于 2024-7-21 15:54 编辑

回复 29# 娜美

前面发的都没计算全角字符
#36 #37  计算了全角,用 ":" 分隔字段

TOP

本帖最后由 ppll2030 于 2024-7-20 23:37 编辑

回复 31# buyiyang


    厉害了。大佬这个应该是完美通用版了。

TOP

本帖最后由 buyiyang 于 2024-7-20 21:55 编辑

回复 25# ppll2030

这个不限列数,还用了两种方法算字符宽度。
  1. @echo off
  2. chcp 437 >nul
  3. set "Separator=@"
  4. set "inputfile=a.txt"
  5. setlocal enabledelayedexpansion
  6. :loop
  7. set /a column+=1
  8. set /a #C%column%max=mark=0
  9. for /f "tokens=%column%" %%i in (%inputfile%) do (
  10.     call :strlen "%%i"
  11.     if !len! geq !#C%column%max! set /a #C%column%max=len
  12.     set mark=1
  13.     )
  14. if %mark% equ 1 goto :loop
  15. set /a column-=1
  16. chcp 936 >nul
  17. set /a lines=0
  18. (for /l %%i in (1,1,%column%) do call :output %%i)>$.temp
  19. set "Separator="&set arg=" delims=%Separator%" "rem"
  20. set "inputfile=$.temp"&(for /l %%i in (1,1,%lines%) do call :output %%i %arg%)>output_%inputfile%
  21. del /q $ $.temp
  22. pause&exit
  23. :strlen
  24. set "str=_%~1"
  25. set "len=0"
  26. for %%n in (64 32 16 8 4 2 1) do (
  27.     if "!str:~%%n,1!" neq "" (
  28.         set/a "len+=%%n"
  29.         set "str=!str:~%%n!"
  30.         )
  31. )
  32. exit /b
  33. :output
  34. if %1 equ 1 goto :output_2
  35. for /f "tokens=1,%1%~2" %%a in (%inputfile%) do (
  36.     if "%%b"=="" (set "field=-") else set "field=%%b"
  37.     %~3 set/p="!field!"<nul>$&for %%i in ($) do (set len=%%~zi)
  38.     %~3 set /a spaceNum=!#C%1max!-len+2,n+=1
  39.     set "outstr=!outstr!%Separator%!field!"
  40.     %~3 for /l %%i in (1,1,!spaceNum!) do set "outstr=!outstr! "
  41.     )
  42. %~3 if %n% geq %lines% set /a lines=n
  43. %~3 set /a n=0
  44. echo,!outstr!
  45. set "outstr="
  46. exit /b
  47. :output_2
  48. for /f "tokens=%1%~2" %%a in (%inputfile%) do (
  49.     if "%%a"=="" (set "field=-") else set "field=%%a"
  50.     %~3 set/p="!field!"<nul>$&for %%i in ($) do (set len=%%~zi)
  51.     %~3 set /a spaceNum=!#C%1max!-len+2,n+=1
  52.     set "outstr=!outstr!%Separator%!field!"
  53.     %~3 for /l %%i in (1,1,!spaceNum!) do set "outstr=!outstr! "
  54.     )
  55. %~3 if %n% geq %lines% set /a lines=n
  56. %~3 set /a n=0
  57. echo,!outstr!
  58. set "outstr="
复制代码

TOP

回复 20# buyiyang

批处理没有格式化输出,要对齐要注意两点:
    1.等宽字体和比例字体。等宽字体每个西文宽度相同,才能对齐;而比例字体会将西文宽度按比例调整以便于观看。中文一般都是等宽的。
    2.全角和半角。半角字符占1个标准字符宽度,西文(包括空格)一般为半角;而全角字符占2个标准字符宽度,中文均为全角。
楼上批处理是根据字节计算宽度的,有findstr算偏移量、for的%%~zi增强扩展算size的,都是根据:
    在ansi(gb2312)编码中一个汉字必须是两个值大于127的字节连在一起,并兼容ASCII。所以一个汉字=2个字节=2个标准字符宽度,一个ASCII字符=1个字节=1个标准字符宽度。
其实可以通过if比较区分每个字符是中文还是英文。
还有通过控制台437代码页将双字节的字符分成两个字符来算字符宽度的方法。
如果是utf-8等其他编码方式则会不同。

TOP

本帖最后由 娜美 于 2024-7-20 13:58 编辑

回复 26# newswan

长度如果不超过宽度基本没有问题

   但如遇到这样的长短都不一
  1. aa          1232    米
  2. bbbbb     66       米
  3. b 66  米
  4. cccccccccccccccccccccccccccccccccccc    c   cccccccccccccccccccccccccccccc  cc   c          米 c
  5. c cc    ccc     v          米
  6. 补补补补补补补补补补补补补补补补补  cccccccccccccccccccccccccccccc          补补补补补补补补补补补补补补补补补       c       c                 c
  7. 补  c                      cccccccccccccccccccccccccccccc    c             c                c
复制代码
想要完全解决问题,  似乎需要检查每1列最后一个空格在什么位置, 记录后一个空格位置数值,  再用空格来填充所有,   才可以彻底解决

TOP

powershell
  1. $file = Get-Content -Path "data.txt" -Encoding UTF8
  2. $maxlen = @(0) *10
  3. $file | ForEach-Object {
  4. $arr = $_  -split "\s+"
  5. for ( $i =0 ; $i -lt $arr.count ; $i++ ){
  6. if ( $maxlen[$i] -lt ($arr[$i]).length ) {
  7. $maxlen[$i] = ($arr[$i]).length
  8. }
  9. }
  10. }
  11. $maxlen = $maxlen -join " " -replace "( 0)*" -split "\s+"
  12. $file | ForEach-Object {
  13. $arr = $_  -split "\s+"
  14. $str = ""
  15. for ( $i =0 ; $i -lt $arr.count ; $i++ ){
  16. $str += ($arr[$i]).PadRight($maxlen[$i]," ") + "  "
  17. }
  18. write-host ( $str -replace "\s$","" )
  19. }
复制代码

TOP

不如将空格换成tab
文本编辑器来打开时会自行处理

TOP

本帖最后由 newswan 于 2024-7-20 01:54 编辑

保存为 a.awk ,然后 awk -f a.awk a.txt
  1. BEGIN {
  2. FS = " "
  3. while ( getline < ARGV[1] ) {
  4. for (i = 1; i <= NF; i++) {
  5. if ( length($i) > maxlen[i] ) {
  6. maxlen[i] = length($i)
  7. }
  8. }
  9. }
  10. }
  11. {
  12. for (i = 1; i <= NF; i++) {
  13. printf "%-*s\t",maxlen[i],$i
  14. }
  15. printf "\r\n"
  16. }
复制代码
1

评分人数

TOP

我也发一个吧。也是用字节数补齐空格的方式。
就是代码啰嗦了一些。而且局限列数为5列。
不知道还能不能精简,望各位老大指点一二。
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. rem 计算字符的字节,cmd下输出是对齐状态,导出txt会变形,需改换等宽字体,cmd默认是Consolas。
  4. REM 获取文本最大字符串的字节
  5. for /f "delims=" %%a in (1.txt) do for %%s in (%%a) do (
  6. set/p="%%s"<nul>$
  7. for %%b in ($) do if %%~zb gtr !maxZ! set "maxZ=%%~zb"
  8. )
  9. for /f "tokens=1-4*  delims= " %%a in (1.txt) do (
  10.     rem 获取每列字符串的字节
  11.     set "a=%%a"&set "b=%%b"&set "c=%%c"&set "d=%%d"&set "e=%%e"
  12.     set/p="%%a"<nul>$&for %%i in ($) do (set az=%%~zi)
  13.     set/p="%%b"<nul>$&for %%i in ($) do (set bz=%%~zi)
  14.     set/p="%%c"<nul>$&for %%i in ($) do (set cz=%%~zi)
  15.     set/p="%%d"<nul>$&for %%i in ($) do (set dz=%%~zi)
  16.     set/p="%%e"<nul>$&for %%i in ($) do (set ez=%%~zi)
  17.     rem 获取每列字符串的字节差,并用空格补齐
  18.     set/a Na=!maxZ!-!az!&set/a Nb=!maxZ!-!bz!&set/a Nc=!maxZ!-!cz!&set/a Nd=!maxZ!-!dz!&set/a Ne=!maxZ!-!ez!
  19.     for /l %%i in (1,1,!Na!) do set "a=!a! "
  20.     for /l %%i in (1,1,!Nb!) do set "b=!b! "
  21.     for /l %%i in (1,1,!Nc!) do set "c=!c! "
  22.     for /l %%i in (1,1,!Nd!) do set  "d=!d! "
  23.     rem for /l %%i in (1,1,!Ne!) do set  "e=!e! "
  24.     echo !a! !b! !c! !d! !e!
  25. )
  26. del/q $&pause&exit
复制代码

TOP

本帖最后由 qixiaobin0715 于 2024-7-19 14:54 编辑

按照各列字节数与最大字节数的差值,然后用空格补齐的方法,适用含有中文字符的列:
  1. @echo off
  2. set colsn=4
  3. set /a colsn-=1
  4. for /f "tokens=1-%colsn%" %%1 in (a.txt) do (
  5.     echo,%%1>>temp1
  6.     echo,%%2>>temp2
  7.     echo,%%3>>temp3
  8. )
  9. setlocal enabledelayedexpansion
  10. for /l %%a in (1,1,%colsn%) do (
  11.     echo,a>>temp%%a
  12.     set /a x=n%%a=0
  13.     for /f "tokens=1,2 delims=:" %%i in ('findstr /n /o .* temp%%a') do (
  14.         set /a "x%%a=%%j-x"
  15.         set /a "m=%%i-1"
  16.         set "n%%a#!m!=!x%%a!"
  17.         if !n%%a! lss !x%%a! set /a "n%%a=x%%a"
  18.         set "x=%%j"
  19.     )
  20.     del temp%%a
  21. )
  22. for /f "tokens=1-%colsn%*" %%1 in (a.txt) do (
  23.     set /a "n+=1"
  24.     set f=
  25.     set "f1=%%1"
  26.     set "f2=%%2"
  27.     set "f3=%%3"
  28.     for /l %%x in (1,1,%colsn%) do (
  29.         set /a "m%%x=n%%x-n%%x#!n!"
  30.         for /l %%y in (1,1,!m%%x!) do set "f%%x=!f%%x! "
  31.         set "f=!f!!f%%x!    "
  32.     )
  33.     echo,!f!%%4
  34. )
  35. pause
复制代码
由于未及仔细考虑,代码存在以下缺点:
1.代码过于复杂,可读性差;
2.除最后一列外,其余各行各列字节数均预先设置变量,处理较大文件时,速度可能会比较慢,甚至超出变量设置的上限而出错;
3.上面代码是按4列文本来处理的,如果列数有变化,需要对以上代码进行修改(虽然写代码时,考虑到了列数变化时,尽量减少修改量),通用性不是太好。

下面举例说明列数变化时,代码调整的方法:
1.如果文本内容的列数为3列,代码做如下调整:
第2行变量值修改为3;
删除第7行;
删除第27行;
将第33行的%%4改为%%3;
2.如果文本内容的列数为5列,代码做如下调整:
第2行变量值修改为5;
第7行下面增加一行:echo,%%4>>temp4
第27行下面增加一行:set "f4=%%4"
将第33行的%%4改为%%5;

TOP

本帖最后由 newswan 于 2024-7-19 14:32 编辑

1 字体的宽度,夹杂中文,更纱一个字体,能完全对齐
2 中文的宽度,上面的所有方案,都没有计算中文宽度,用制表符处理误差,一旦前面中文过多,也不能对齐。

TOP

回复 20# buyiyang


    感谢解惑。更换字体后txt文件得到对齐的结果了。

TOP

返回列表