AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / unix / Perguntas / 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

Alinhando visualmente as colunas de um arquivo CSV

  • 772

Usando sedou awk, é possível alinhar visualmente colunas em um arquivo CSV?

Por exemplo:

por exemplo de:

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

para:

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>

Existem alguns campos com aspas duplas contendo texto e vírgulas.

Eu tentei column, mas aparentementebsdmainutils não é capaz de lidar com esses dados.

csv
  • 3 3 respostas
  • 285 Views

3 respostas

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

    Um arquivo CSV deste tipo:

    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>
    

    não é mais o mesmo arquivo de dados, pois você está modificando os campos. Quando analisado, o que era originalmente "t"agora será analisado por " t"causa da largura "some stuff"acima (a menos que você use um regex para analisar os delimitadores não padrão ,[variable space]).

    Você pode forçar aspas em todos os campos para obter um arquivo mais csv que mostre esses novos campos claramente. Aqui está um Ruby para fazer isso:

    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
    

    Estampas:

    "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"
    

    Ou, se você realmente deseja campos entre aspas e sem aspas, você pode fazer:

    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
    

    Estampas:

    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
    

    Que também lida com aspas de escape desagradáveis ​​dentro dos campos. Dado:

    $ 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 segunda versão imprime:

    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

    Existem alguns campos com aspas duplas contendo texto e vírgulas.

    Esqueça a análise de texto simples então. Basta obter algo que possa analisar CSV complexo e deixar que faça a impressão bonita.

    Miller é a ferramenta de escolha. Você pode especificar "pretty print" como formato de saída:

    mlr --icsv --opprint cat example.csv
    

    Você também pode usar apenas o módulo interno do 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

    Usando GNU awk for FPATe uma abordagem de 2 passos:

    $ 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
    

    Alternativamente, a mesma abordagem usando qualquer awk onde você só precisa escrever o código para dividir cada registro em campos usando um loop chamando match()e FPATarmazenando esses campos em uma matriz em vez do acima, onde o gawk faz isso para você como parte do campo normal divisão:

    $ 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
    

    Em vez de ler a entrada duas vezes, você pode, alternativamente, armazenar toda a entrada na memória e, em seguida, imprimir tudo na seção END, o que tem a vantagem de funcionar na entrada proveniente de um tubo e a desvantagem de que falharia se o seu arquivo de entrada era muito grande para caber na memória. Aqui está a versão GNU awk disso:

    $ 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
    

    e qualquer versão do 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

relate perguntas

  • adicionar vírgula antes de determinado caractere

  • compare 2 arquivos csv e gere apenas a diferença na variável

  • Transforme xlsx em csv no AIX quando não houver ferramenta para fazer isso [fechado]

  • Transforme .CSV existente comparando a linha anterior com cálculos atuais e secundários

  • Verificando se um arquivo de texto possui todas as entradas e está formatado corretamente

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Possível firmware ausente /lib/firmware/i915/* para o módulo i915

    • 3 respostas
  • Marko Smith

    Falha ao buscar o repositório de backports jessie

    • 4 respostas
  • Marko Smith

    Como exportar uma chave privada GPG e uma chave pública para um arquivo

    • 4 respostas
  • Marko Smith

    Como podemos executar um comando armazenado em uma variável?

    • 5 respostas
  • Marko Smith

    Como configurar o systemd-resolved e o systemd-networkd para usar o servidor DNS local para resolver domínios locais e o servidor DNS remoto para domínios remotos?

    • 3 respostas
  • Marko Smith

    apt-get update error no Kali Linux após a atualização do dist [duplicado]

    • 2 respostas
  • Marko Smith

    Como ver as últimas linhas x do log de serviço systemctl

    • 5 respostas
  • Marko Smith

    Nano - pule para o final do arquivo

    • 8 respostas
  • Marko Smith

    erro grub: você precisa carregar o kernel primeiro

    • 4 respostas
  • Marko Smith

    Como baixar o pacote não instalá-lo com o comando apt-get?

    • 7 respostas
  • Martin Hope
    user12345 Falha ao buscar o repositório de backports jessie 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl Por que a maioria dos exemplos do systemd contém WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky Como exportar uma chave privada GPG e uma chave pública para um arquivo 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll status systemctl mostra: "Estado: degradado" 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim Como podemos executar um comando armazenado em uma variável? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S Por que /dev/null é um arquivo? Por que sua função não é implementada como um programa simples? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 Como ver as últimas linhas x do log de serviço systemctl 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - pule para o final do arquivo 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla Por que verdadeiro e falso são tão grandes? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis Substitua a string em um arquivo de texto enorme (70 GB), uma linha 2017-12-30 06:58:33 +0800 CST

Hot tag

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

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve