Contar o número de campos em cada registro csv

12

Imagine um arquivo de texto em que cada registro csv possa ter diferentes números de campos. A tarefa é escrever código para gerar quantos campos existem em cada registro do arquivo. Você pode assumir que não há linha de cabeçalho no arquivo e pode ler de um arquivo ou entrada padrão, conforme desejar.

Você pode assumir uma versão do rfc4180 para as regras csv que explicarei abaixo para a definição de cada linha do arquivo. Aqui está uma versão levemente editada da parte relevante da especificação:

Definição do formato CSV

  1. Cada registro está localizado em uma linha separada, delimitada por uma quebra de linha (CRLF). Por exemplo:

    aaa,bbb,ccc CRLF
    zzz,yyy,xxx CRLF

  2. O último registro no arquivo pode ou não ter uma quebra de linha final. Por exemplo:

    aaa,bbb,ccc CRLF
    zzz,yyy,xxx

(A regra 3. não se aplica neste desafio)

  1. Dentro de cada registro, pode haver um ou mais campos, separados por vírgulas. Os espaços são considerados parte de um campo e não devem ser ignorados.

  2. Cada campo pode ou não estar entre aspas duplas. Se os campos não estiverem entre aspas duplas, as aspas duplas podem não aparecer dentro dos campos. Por exemplo:

    "aaa","bbb","ccc" CRLF
    zzz,yyy,xxx

  3. Os campos que contêm quebras de linha (CRLF), aspas duplas e vírgulas devem ser colocados entre aspas duplas. Por exemplo:

    "aaa","b CRLF
    bb","ccc" CRLF
    zzz,yyy,xxx

  4. Se aspas duplas forem usadas para delimitar campos, uma aspas dupla aparecendo dentro de um campo deverá ser escapada precedendo-a com outra aspas dupla. Por exemplo:

    "aaa","b""bb","ccc"

Exemplo

Entrada:

,"Hello, World!"
"aaa","b""bb","ccc"
zzz,yyy,
"aaa","b 
bb","ccc","fish",""

Deve dar a saída:

2, 3, 3, 5

Você pode fornecer os valores de saída da maneira que achar mais conveniente.

Bibliotecas

Você pode usar qualquer biblioteca que desejar.


Respostas impressionantes até agora, mas falta uma resposta de linha de comando / bash que seria particularmente interessante.

Anush
fonte

Respostas:

5

Stax , 19 12 bytes

èJ§3‼}vAà○L>

Execute e depure

Descompactado, não jogado e comentado, parece com isso.

_'"/    split *all* of standard input by double quote characters
2::     keep only the even numbered elements
|j      split on newlines (implicitly concatenates array of "strings")
m       for each line, execute the rest of the program and output
  ',#^  count the number of commas occurring as substrings, and increment

Execute este

recursivo
fonte
1
Como funciona?
Anush
1
@ Anush: Adicionei mais algumas informações.
recursivo
4

R , 40 bytes

(x=count.fields(stdin(),","))[!is.na(x)]

Experimente online!

De acordo com a documentação de count.fields, os campos com quebras de linha obtêm uma contagem de campos de NA para a linha inicial, portanto os filtramos.

Giuseppe
fonte
3

JavaScript (ES2018), 42 59 bytes

s=>s.replace(/".+?"/sg).split`\n`.map(c=>c.split`,`.length)

Rick Hitchcock
fonte
Tecnicamente, este é o ES2018 devido à sbandeira no regex. Não que isso importe tanto ;-) E bom uso, btw!
ETHproductions
2
Esta função parece funcionar apenas em um registro de cada vez. Eu acho que a descrição do problema requer a manipulação de um arquivo inteiro de vários registros.
recursivo
@ETHproductions, bom ponto, será atualizado.
Rick Hitchcock
@ recursivo, você está certo, eu entendi mal as entradas. Agora atualizado, com a perda de muitos bytes.
Rick Hitchcock
3

Gelatina , 12 bytes

ṣ”"m2FỴ=”,§‘

Uma resposta Stax recursiva - vá dar crédito!

Experimente online!

Quão?

ṣ”"m2FỴ=”,§‘ - Link: list of characters, V
 ”"          - a double quote character = '"'
ṣ            - split (V) at ('"')
   m2        - modulo slice with two (1st, 3rd, 5th, ... elements of that)
     F       - flatten list of lists to a list
      Ỵ      - split at newlines
        ”,   - comma character = ','
       =     - equal? (vectorises)
          §  - sum each
           ‘ - increment (vectorises)
             - (as a full program implicit print)

Talvez você prefira ṣ”"m2ẎỴċ€”,‘- é apertar e ċ€conta as vírgulas em cada uma.

Jonathan Allan
fonte
2

Python, 63 bytes

import csv
def f(s):return map(len,csv.reader(s.split("\n"))

Retorna a saída em um mapobjeto iterável .

SlayerGames44
fonte
2
Usando uma lambdafunção, você pode
reduzi-
@ovs Talvez eu não entenda as regras, mas seu TIO parece ter preparado a entrada. Isso é realmente válido?
Anush
Entendo por que ele funciona agora (graças a apenas @ ASCII).
Anush
2

Perl 5 .10.0, 55 53 bytes

$_=shift;s/"(""|[^"])*"//g;s/^.*$/1+$&=~y:,::/gem;say

Experimente online!

Explicação:

$_=shift;          # first command-line arg
s/"(""|[^"])*"//g; # remove quoted fields
s/^.*$/            # replace each line       
  1+$&=~y:,::      # by the number of commas plus 1
/gem;
say                # print
wastl
fonte
2

Java 10, 101 bytes

s->{for(var p:s.replaceAll("\"[^\"]*\"","x").split("\n"))System.out.println(p.split(",",-1).length);}

Experimente online.

Explicação:

s->{                                    // Method with String parameter and no return-type
  for(var p:s.replaceAll("\"[^\"]*\"","x") 
                                        //  Replace all words within quotes with an "x"
             .split("\n"))              //  Then split by new-line and loop over them:
    System.out.println(p.split(",",-1)  //   Split the item by comma's
                        .length);}      //   And print the length of this array
Kevin Cruijssen
fonte