AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 739338
Accepted
s.k
s.k
Asked: 2023-03-11 01:43:20 +0800 CST2023-03-11 01:43:20 +0800 CST 2023-03-11 01:43:20 +0800 CST

视觉对齐 CSV 文件的列

  • 772

使用sedor awk,是否可以在视觉上对齐 CSV 文件中的列?

例如:

例如来自:

a,b,c,some stuff,"some, other, stuff",d,2023-03-10 18:37:00
y,x,z,t,cool,thing,2022-04-12 21:44:00

到:

a, b, c, some stuff,"some, other, stuff",     d, 2023-03-10 18:37:00<EOL>
x, y, z,          t,                cool, thing, 2022-04-12 21:44:00<EOL>

有一些双引号字段包含文本和逗号。

我尝试column了bsdmainutils一下,但显然无法处理此类数据。

csv
  • 3 3 个回答
  • 285 Views

3 个回答

  • Voted
  1. drewk
    2023-03-11T03:27:48+08:002023-03-11T03:27:48+08:00

    这种类型的 CSV 文件:

    a, b, c, some stuff,"some, other, stuff",     d, 2023-03-10 18:37:00<EOL>
    x, y, z,          t,                cool, thing, 2022-04-12 21:44:00<EOL>
    

    因为您正在修改字段,所以不再是同一个数据文件。解析时,由于上面的宽度,原来的内容"t"现在将解析出来(除非您使用正则表达式来解析非标准分隔符。)" t""some stuff",[variable space]

    您可以在所有字段上强制加引号以获得更清楚地显示这些新字段的 csv 文件。这是一个 Ruby 来做到这一点:

    ruby -r csv -e '
    cols={}
    data=CSV.parse($<.read)
    data.transpose.each_with_index{|sa,i| 
        cols[i]=sa.max_by{|e| e.length}; cols[i]=cols[i].length 
    }
    puts CSV.generate(force_quotes:true){|csv|
        data.each{|row|
            csv<<row.map.with_index{|e, i| e.rjust(cols[i] ) }
        }
    }
    ' file
    

    印刷:

    "a","b","c","some stuff","some, other, stuff","    d","2023-03-10 18:37:00"
    "y","x","z","         t","              cool","thing","2022-04-12 21:44:00"
    

    或者,如果您真的想要引用和未引用的字段,您可以执行以下操作:

    ruby -r csv -e '
    lcl_csv_opt={:row_sep=>nil}
    data=CSV.parse($<.read)
    cols=data.transpose.map.with_index{|sa,i| 
        x=sa.max_by{|e| [e].to_csv(**lcl_csv_opt).length}
        [i,"#{[x].to_csv(**lcl_csv_opt)}"]
    }.to_h
    puts CSV.generate(){|csv|
        data.each{|row|
            csv<<row.map.with_index{|e, i| 
                [e].to_csv(**lcl_csv_opt)==cols[i] ? e : e.rjust(cols[i].length ) 
            }
        }
    }
    ' file
    

    印刷:

    a,b,c,some stuff,"some, other, stuff",    d,2023-03-10 18:37:00
    y,x,z,         t,                cool,thing,2022-04-12 21:44:00
    

    它还处理字段中令人讨厌的转义引号。鉴于:

    $ cat file
    a,b,c,some stuff,"some, other, stuff",d,2023-03-10 18:37:00
    y,x,z,t,cool,"""thing"", quoted",2022-04-12 21:44:00
    

    第二个版本打印:

    a,b,c,some stuff,"some, other, stuff",                  d,2023-03-10 18:37:00
    y,x,z,         t,                cool,"""thing"", quoted",2022-04-12 21:44:00
    
    • 7
  2. Best Answer
    Marcus Müller
    2023-03-11T01:59:28+08:002023-03-11T01:59:28+08:00

    有一些双引号字段包含文本和逗号。

    那就忘掉简单的文本解析吧。只需获取可以解析复杂 CSV 的东西,然后让它进行漂亮的打印。

    米勒是首选工具。您可以指定“漂亮的打印”作为输出格式:

    mlr --icsv --opprint cat example.csv
    

    您也可以只使用 Python 的内置csv模块:

    import csv
    
    rows = []
    maxwidths = []
    with open("foo.csv") as csvfile:
        reader = csv.reader(csvfile, delimiter=",", quotechar='"')
        for row in reader:
            for column_idx, entry in enumerate(row):
                if column_idx >= len(maxwidths):
                    maxwidths += [len(entry)]
                else:
                    maxwidths[column_idx] = max(maxwidths[column_idx], len(entry))
            rows += [row]
    
    for row in rows:
        print(", ".join([f"{col:<{width}}" for col, width in zip(row, maxwidths)]))
    
    • 6
  3. Ed Morton
    2023-03-11T19:30:51+08:002023-03-11T19:30:51+08:00

    使用 GNU awkFPAT和 2 pass 方法:

    $ cat tst.awk
    BEGIN {
        FPAT = "([^,]*)|(\"([^\"]|\"\")*\")"
        OFS = ", "
    }
    NR==FNR {
        for ( i=1; i<=NF; i++ ) {
            wid = length($i)
            wids[i] = ( wid > wids[i] ? wid : wids[i] )
        }
        next
    }
    {
        for ( i=1; i<=NF; i++ ) {
            printf "%*s%s", wids[i], $i, (i<NF ? OFS : ORS)
        }
    }
    

    $ awk -f tst.awk file file
    a, b, c, some stuff, "some, other, stuff",     d, 2023-03-10 18:37:00
    y, x, z,          t,                 cool, thing, 2022-04-12 21:44:00
    

    或者,使用任何 awk 的相同方法,您只需要自己编写代码,使用循环调用将每条记录拆分为字段,match()并将FPAT这些字段存储在数组中,而不是上面的 gawk 作为普通字段的一部分为您做的拆分:

    $ cat tst.awk
    BEGIN {
        FPAT = "([^,]*)|(\"([^\"]|\"\")*\")"
        OFS = ", "
    }
    {
        nf = 0
        rec = $0
        while ( (rec != "") && match(rec,FPAT) ) {
            flds[++nf] = substr(rec,RSTART,RLENGTH)
            rec = substr(rec,RSTART+RLENGTH+1)
        }
    }
    NR==FNR {
        for ( i=1; i<=nf; i++ ) {
            wid = length(flds[i])
            wids[i] = ( wid > wids[i] ? wid : wids[i] )
        }
        next
    }
    {
        for ( i=1; i<=nf; i++ ) {
            printf "%*s%s", wids[i], flds[i], (i<nf ? OFS : ORS)
        }
    }
    

    $ awk -f tst.awk file file
    a, b, c, some stuff, "some, other, stuff",     d, 2023-03-10 18:37:00
    y, x, z,          t,                 cool, thing, 2022-04-12 21:44:00
    

    您可以将整个输入存储在内存中,然后将其全部打印在 END 部分,而不是读取输入两次,其优点是它可以处理来自管道的输入,缺点是如果您的输入会失败输入文件太大,内存放不下。这是它的 GNU awk 版本:

    $ cat tst.awk
    BEGIN {
        FPAT = "([^,]*)|(\"([^\"]|\"\")*\")"
        OFS = ", "
    }
    {
        for ( i=1; i<=NF; i++ ) {
            flds[NR,i] = $i
            wid = length($i)
            wids[i] = ( wid > wids[i] ? wid : wids[i] )
        }
    }
    END {
        for ( rowNr=1; rowNr<=NR; rowNr++ ) {
            for ( i=1; i<=NF; i++ ) {
                printf "%*s%s", wids[i], flds[rowNr,i], (i<NF ? OFS : ORS)
            }
        }
    }
    

    $ awk -f tst.awk file
    a, b, c, some stuff, "some, other, stuff",     d, 2023-03-10 18:37:00
    y, x, z,          t,                 cool, thing, 2022-04-12 21:44:00
    

    和任何 awk 版本:

    $ cat tst.awk
    BEGIN {
        FPAT = "([^,]*)|(\"([^\"]|\"\")*\")"
        OFS = ", "
    }
    {
        nf = 0
        rec = $0
        while ( (rec != "") && match(rec,FPAT) ) {
            fld = substr(rec,RSTART,RLENGTH)
            flds[NR,++nf] = fld
            wid = length(fld)
            wids[nf] = ( wid > wids[nf] ? wid : wids[nf] )
            rec = substr(rec,RSTART+RLENGTH+1)
        }
    }
    END {
        for ( rowNr=1; rowNr<=NR; rowNr++ ) {
            for ( i=1; i<=nf; i++ ) {
                printf "%*s%s", wids[i], flds[rowNr,i], (i<nf ? OFS : ORS)
            }
        }
    }
    

    $ awk -f tst.awk file
    a, b, c, some stuff, "some, other, stuff",     d, 2023-03-10 18:37:00
    y, x, z,          t,                 cool, thing, 2022-04-12 21:44:00
    
    • 3

相关问题

  • 在某些字符前添加逗号

  • 比较 2 个 csv 文件并仅将差异输出到变量中

  • 在没有工具的情况下在 AIX 中将 xlsx 转换为 csv [关闭]

  • 通过将前一行与当前和次要计算进行比较来转换现有的 .CSV

  • 检查文本文件是否包含所有条目并且格式正确

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    模块 i915 可能缺少固件 /lib/firmware/i915/*

    • 3 个回答
  • Marko Smith

    无法获取 jessie backports 存储库

    • 4 个回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    user12345 无法获取 jessie backports 存储库 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl 为什么大多数 systemd 示例都包含 WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve