Cuente el número de campos en cada registro csv

12

Imagine un archivo de texto donde cada registro csv puede tener diferentes números de campos. La tarea es escribir código para generar cuántos campos hay en cada registro del archivo. Puede suponer que no hay una línea de encabezado en el archivo y puede leer desde un archivo o entrada estándar, según lo elija.

Puede asumir una versión de rfc4180 para las reglas csv que explicaré a continuación para la definición de cada línea del archivo. Aquí hay una versión ligeramente editada de la parte relevante de la especificación:

Definición del formato CSV

  1. Cada registro está ubicado en una línea separada, delimitada por un salto de línea (CRLF). Por ejemplo:

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

  2. El último registro en el archivo puede o no tener un salto de línea final. Por ejemplo:

    aaa,bbb,ccc CRLF
    zzz,yyy,xxx

(La regla 3. no se aplica en este desafío)

  1. Dentro de cada registro, puede haber uno o más campos, separados por comas. Los espacios se consideran parte de un campo y no se deben ignorar.

  2. Cada campo puede estar o no encerrado entre comillas dobles. Si los campos no están encerrados entre comillas dobles, entonces las comillas dobles pueden no aparecer dentro de los campos. Por ejemplo:

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

  3. Los campos que contienen saltos de línea (CRLF), comillas dobles y comas deben ir entre comillas dobles. Por ejemplo:

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

  4. Si se usan comillas dobles para encerrar campos, entonces se debe escapar una comilla doble que aparece dentro de un campo precediéndola con otra comilla doble. Por ejemplo:

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

Ejemplo

Entrada:

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

Debería dar la salida:

2, 3, 3, 5

Puede proporcionar los valores de salida de la forma que le resulte más conveniente.

Bibliotecas

Puedes usar cualquier biblioteca que quieras.


Respuestas impresionantes hasta ahora, pero nos falta una respuesta de línea de comando / bash que sería particularmente genial.

Anush
fuente

Respuestas:

5

Stax , 19 12 bytes

èJ§3‼}vAà○L>

Ejecutar y depurarlo

Desempaquetado, sin golf y comentado, se ve así.

_'"/    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

Ejecute este

recursivo
fuente
1
¿Como funciona?
Anush
1
@Anush: he agregado más información.
recursivo
4

R , 40 bytes

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

Pruébalo en línea!

Según la documentación de count.fields, los campos con saltos de línea obtienen un recuento de campos de NA para la línea inicial, por lo que los filtramos.

Giuseppe
fuente
3

JavaScript (ES2018), 42 59 bytes

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

Rick Hitchcock
fuente
Técnicamente, esto es ES2018 debido a la sbandera en la expresión regular. No es que importe tanto ;-) ¡Y buen uso, por cierto!
ETHproductions
2
Esta función solo parece funcionar en un registro a la vez. Creo que la descripción del problema requiere manejar un archivo completo de múltiples registros.
recursivo
@ETHproductions, buen punto, se actualizará.
Rick Hitchcock
@recursivo, tienes razón, no entendí las entradas. Ahora actualizado, con la pérdida de muchos muchos bytes.
Rick Hitchcock
3

Jalea , 12 bytes

ṣ”"m2FỴ=”,§‘

La respuesta Stax de un puerto recursivo : ¡ve a dar crédito!

Pruébalo en línea!

¿Cómo?

ṣ”"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)

Tal vez prefiera ṣ”"m2ẎỴċ€”,‘: es apretar y ċ€cuenta las comas en cada uno.

Jonathan Allan
fuente
2

Python, 63 bytes

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

Devuelve la salida en un mapobjeto iterable .

SlayerGames44
fuente
2
Usando una lambdafunción puede reducir esto a 54 bytes
ovs
@ovs Puede que no entienda las reglas, pero su TIO parece haber preparado previamente la entrada. ¿Es eso realmente válido?
Anush
Veo por qué funciona ahora (gracias solo a @ ASCII).
Anush
2

Perl 5 .10.0, 55 53 bytes

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

Pruébalo en línea!

Explicación:

$_=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
fuente
2

Java 10, 101 bytes

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

Pruébalo en línea.

Explicación:

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
fuente