Converti CSV in tabella


15

La sfida

Dato un input CSV, emette una tabella unicode corretta usando i caratteri box.

Formattazione

La tabella verrà formattata utilizzando le seguenti regole:

  • La larghezza della colonna sarà uguale al valore più lungo di quella colonna
  • Tutti i dati della tabella verranno lasciati giustificati
  • Ogni tabella assumerà la prima riga CSV come intestazione
  • La tabella utilizzerà i seguenti caratteri per i suoi bordi:

┌ ┬ ┐ ├ ┼ ┤ └ ┴ ┘ ─ │

Esempio

Input:
Name,Age,Gender
Shaun,19,Male
Debra,19,Female
Alan,26,Male
George,15,Male

Output:
┌──────┬───┬──────┐
│Name  │Age│Gender│
├──────┼───┼──────┤
│Shaun │19 │Male  │
│Debra │19 │Female│
│Alan  │26 │Male  │
│George│15 │Male  │
└──────┴───┴──────┘

Regole

  • Si applicano scappatoie standard
  • È possibile inviare un programma completo, una funzione o un lambda
  • L'input può provenire da un file, un argomento del programma o qualsiasi alternativa accettabile
  • L'output può essere su un file, restituito o qualsiasi alternativa accettabile
  • L'input CSV dovrebbe avere lo stesso formato usato nel mio esempio.
  • Vince la risposta più breve in byte.

L'input CSV dovrebbe assumere la forma seguente:

Header1,Header2,Header3 newline
Column1,Column2,Column3 newline
Column1,Column2,Column3 optional_newline

2
Penso che ci siano fondamentalmente due modi in cui puoi andare con la definizione CSV. Se la parte interessante del problema è l'output, puoi renderlo semplice come "diviso in virgole" e non devi preoccuparti di come citare le virgole e come citare il carattere di citazione. Altrimenti, potresti indicare un metodo specifico di analisi del CSV ("virgolette doppie commutano una modalità in cui le virgole vengono ignorate, due virgolette doppie in una riga producono una doppia virgoletta letterale" è abbastanza comune, ma non è assolutamente l'unica in esistenza).

4
Err, problema serio: non hai specificato una condizione di vittoria. Per che cosa devono essere ottimizzati i programmi? Lunghezza ( code-golf )?

1
Almeno i primi tre collegamenti lì definiscono tutti CSV in modo diverso (e almeno due dicono che ci sono molti modi diversi per farlo). Quindi suppongo che "CSV" debba essere definito in modo più completo per l'uso in una domanda (e che le soluzioni proveranno a cavarsela con le virgole e non gestendo la fuga perché consente loro di essere più brevi).

2
Va bene ho modificato la domanda per includere dettagli sul formato CSV che vorrei che tutti usassero.
Shaun Wild,

1
CRLF? Sul serio? Questo comporterà una penalità abbastanza grande su Unix, dove CR significa qualcos'altro nei file di testo. Probabilmente vuoi semplicemente sostituirlo con "newline", consentendo di utilizzare la newline specifica del sistema operativo.

Risposte:


10

Prova (Dyalog) APL , 38 43 byte

L'ultima riga di input deve avere una nuova riga finale.

{{(⊃⍵)⍪⍉⍪↑¨↓⍉↑1↓⍵}s¨',',¨(s1↓¨⊢⊂⍨⊢=⊃)¯1⌽⍵}

Provalo online! Nella versione offline di Dyalog APL, esegui ]boxing ON -style=minper lo stesso effetto.

Spiegazione

{... }una funzione anonima in cui rappresenta l'argomento:

¯1 ⌽ ⍵ ruota la nuova riga finale in avanti

(s ←... )definire la funzione s come segue e applicarla

  1 ↓¨ rilascia il primo carattere di ciascuno

  ⊢ ⊂⍨ linea, dividere dove

  ⊃ = ⊢ il primo carattere è uguale ai caratteri nella stringa

',' ,¨ quindi anteporre una virgola a ciascuna riga

applica la funzione s ad ogni riga

{... }ora applica la seguente funzione anonima:

  1 ↓ ⍵ rilascia il primo elemento (le intestazioni di riga)

  ↓ ⍉ ↑ trasporre l'elenco di righe in un elenco di colonne

  ↑¨ trasforma ogni elemento (un elenco di voci) in una matrice di voci imbottite

  ⍉ ⍪ trasformalo in matrice a una colonna, quindi trasponi in matrice a una riga

  (⊃⍵) ⍪ metti in primo piano il primo elemento dell'argomento (l'elenco delle intestazioni) »

Nota: sebbene i caratteri di disegno al tratto non vengano esplicitamente utilizzati nella mia soluzione, fanno parte del set di caratteri APL e verrebbero conteggiati anche come singoli byte.


Vedi i commenti sopraIs input using list or array of strings (and no newlines) valid? Nope.
edc65,

@ edc65 Risolto. Grazie.
Adám,

Ah, quel display in scatola sicuramente tornerà utile :)
Ven

2

PowerShell 3+, 365 byte

$d=$input|ipcsv
$h=$d[0].PSObject.Properties.Name|%{$_|Add-Member -type NoteProperty -na c -v(($d.$_+$_|measure Length -ma).Maximum)-pa}
"┌$(($h|%{'─'*$_.c})-join'┬')┐"
"│$(($h|%{$_.PadRight($_.c)})-join'│')│"
"├$(($h|%{'─'*$_.c})-join'┼')┤"
$d|%{$i=$_;"│$(($h|%{$i.$_.PadRight($_.c)})-join'│')│"}
"└$(($h|%{'─'*$_.c})-join'┴')┘"

Sento che questo potrebbe essere migliorato molto ma ho finito il tempo. Tutte le terminazioni di riga sono \nsenza \r, la codifica è UTF8 senza BOM.


1

Racchetta 578 byte

(let*((ll(map(λ(x)(string-split x","))ll))(lr list-ref)(sl string-length)(d display)(dl displayln)(nc(length(lr ll 0)))
(nl(for/list((i nc))(apply max(for/list((j ll))(sl(lr j i))))))(pl(λ(sy)(d(lr sy 0))(for((n nc))(for((m(lr nl n)))(d(lr sy 1)))
(if(< n(sub1 nc))(d(lr sy 2))(dl(lr sy 3))))))(g(λ(i n)(for((m(-(lr nl n)(sl i))))(d" ")))))(pl'("┌""─""┬""┐"))
(for((i(lr ll 0))(n(in-naturals)))(d"│")(d i)(g i n))(dl"│")(pl'("├""─""┼""┤"))(for((j(range 1(length ll))))
(for((i(lr ll j))(n nc))(d"│")(d i)(g i n))(dl"│"))(pl'("└" "─" "┴" "┘")))

Ungolfed:

(define(f1 ll)
 (let* ((ll (map (λ (x)(string-split x ",")) ll))  ; use this to convert csv format to list of lists; 
         (lr list-ref)                    ; make short names of standard fns
         (sl string-length)
         (d display)
         (dl displayln)
         (nc (length (lr ll 0)))          ; number of cols; 
         (nl(for/list ((i nc))            ; get list of max string-length for each column
              (apply max
                     (for/list ((j ll))
                       (sl (lr j i))
                       ))))
         (pl (λ (sy)                      ; put lines using sent symbol list
               (d (lr sy 0)) 
               (for ((n nc))
                 (for ((m (lr nl n))) (d (lr sy 1)))
                 (if (< n (sub1 nc))
                     (d (lr sy 2))
                     (dl (lr sy 3))
                     ))))
         (g (λ (i n)                     ; pad with spaces if needed
              (for ((m (- (lr nl n) (sl i)))) (d " ")) ))) 
    ; put line above header: 
    (pl '("┌" "─" "┬" "┐"))

    ; put header: 
    (for ((i (lr ll 0)) (n (in-naturals)))
      (d "│")
      (d i)
      (g i n)
      )
    (dl "│")

    ; put line below header;
    (pl '("├" "─" "┼" "┤"))

    ; put rows: 
    (for ((j (range 1 (length ll))))
      (for ((i (lr ll j))
            (n nc))
        (d "│")
        (d i)
        (g i n)
        )
      (dl "│")
      )

    ; put bottom line: 
    (pl '("└" "─" "┴" "┘"))
    ))

test:

(f (list  "Name,Age,Gender"
          "Shaun,19,Male"
          "Debra,19,Female"
          "Alan,26,Male"
          "George,15,Male"))

Produzione:

┌──────┬───┬──────┐
│Name  │Age│Gender│
├──────┼───┼──────┤
│Shaun │19 │Male  │
│Debra │19 │Female│
│Alan  │26 │Male  │
│George│15 │Male  │
└──────┴───┴──────┘

1

JavaScript (ES6 | FireFox), 286 byte

f=>(d=f.split`
`.map(a=>a.split`,`),s=d[0].map((a,i)=>d.reduce((b,c)=>(n=c[i].length)>b?n:b,0)),d=d.map(a=>`│${a.map((b,i)=>b.padEnd(s[i])).join`│`}│`),d.splice(1,0,(g=h=>h[0]+s.map(a=>'─'.repeat(a)).join(h[1])+h[2])('├┼┤')),g('┌┬┐')+`
${d.join`
`}
`+g('└┴┘'))

Usi padEnd, che è specifico di FireFox.


1
Non sono 288 byte?
Adám,

1
@Adám ... sì ... Risolto
Mwr247,

Usi molto, non è g('└┴┘')equivalente a g└┴┘(con i backtick dopo ge alla fine)?
NoOneIsHere il

1
padEndnon è standard. È necessario specificare l'ambiente di esecuzione necessario.
Neil,

1
Inoltre, ci sono un paio di posti in cui scrivi `foo`+bar+`baz`: puoi salvare un byte usando un modello `foo${bar}baz`.
Neil,

1

JavaScript (ES6), 281 byte

Nota: immettere come singola stringa con newline - come richiesto dall'OP. Altre risposte usano un elenco di stringhe - usando una matrice di stringhe in input posso evitare la prima divisione e tagliare 9 byte.

l=>(l=l.split`
`.map(r=>r.split`,`.map((w,i)=>(v=w.length)<c[i]?w:(c[i]=v,w)),c=[k=0]),l=l.map(r=>r.map((v,i)=>(v+' '.repeat(c[i]-v.length)))),[h=c.map(x=>'─'.repeat(x)),l.shift(),h,...l,h].map(a=>'│┌├└'[j=a!=h?0:++k]+a.join('│┬┼┴'[j])+'│┐┤┘'[j]).join`
`)

Meno golf

l=>(
  // split input in an array of string arrays
  // meanwhile find the column widths and put them in *c*
  l = l.split`\n`.map(r=>r.split`,`.map((w,i)=>(v=w.length)<c[i]?w:(c[i]=v,w)),c=[]),

  // pad each column to the max column width
  l = l.map(r=>r.map((v,i)=>(v+' '.repeat(c[i]-v.length)))),

  // put in *h* the horizontal lines for top,bottom and head separator
  h = c.map(x => '─'.repeat(x) ),

  // add the *h* line at top, bottom and after head line
  l = [h, l.shift(), h, ...l, h],

  // rebuild a string, joining columns with '|' unless the row is *h*
  // if the row is *h* use different characters to join columns
  k = 0, 
  l.map(a=> '│┌├└'[j=a!=h?0:++k] + a.join('│┬┼┴'[j]) + '│┐┤┘'[j])
  .join`\n`  
)

Test

F=
l=>(l=l.split`
`.map(r=>r.split`,`.map((w,i)=>(v=w.length)<c[i]?w:(c[i]=v,w)),c=[k=0]),l=l.map(r=>r.map((v,i)=>(v+' '.repeat(c[i]-v.length)))),[h=c.map(x=>'─'.repeat(x)),l.shift(),h,...l,h].map(a=>'│┌├└'[j=a!=h?0:++k]+a.join('│┬┼┴'[j])+'│┐┤┘'[j]).join`
`) 
  
function update() {
  O.textContent = F(I.value)
}
update()
#I { width:60%; height: 8em} 
<textarea id=I>Name,Age,Gender
Shaun,19,Male
Debra,19,Female
Alan,26,Male
George,15,Male</textarea><br>
<button onclick='update()'>Go</button>
<pre id=O></pre>


0

Python 3, 318 byte

-3 byte per l'utilizzo della %formattazione e -1 per l'abbreviazionestr.join

L=[c.split(',')for c in input().split('\n')]
m=[max(len(x)for x in c)for c in zip(*L)]
L=[[""]+[d.ljust(n)for d,n in zip(c,m)]+[""]for c in L]
g=["─"*i for i in m]
J=str.join
print('\n'.join(["┌%s┐"%J("┬",g),J("│",L[0]),"├%s┤"%J("┼",g)]+[J("│",L[i])for i in range(1,len(L))]+["└%s┘"%J("┴",g)]))

Richiede input racchiuso tra virgolette.


1
A me sembrano 318 byte.
Adám,

1
@Adám Hai ragione, ho guardato i caratteri.
Karl Napf,

Non funziona, perché input()richiede solo una linea per ogni chiamata. Dovrai chiamare input()fino a quando non ci sono più linee o leggere direttamente da stdin.
movatica,

Oltre a ciò: 292 byte
movatica

0

C #, 696 byte

golfed:

string T(string[]f){int w=f.Max(r=>r.Length),a=f.Select(r=>r.Split(',')[0].Length).Max(),b=f.Select(r=>r.Split(',')[1].Length).Max(),c=f.Select(r=>r.Split(',')[2].Length).Max();string o="",n="\r\n",d="",j=string.Concat(Enumerable.Repeat("─",a)),k=string.Concat(Enumerable.Repeat("─",b)),l=string.Concat(Enumerable.Repeat("─",c));Func<string,int,string>z=(q,p)=>{return q.PadRight(p);};d="┌"+j+"┬"+k+"┬"+l+"┐";o+=d+n;var g=f.First().Split(',');o+="|"+z(g[0],a)+"|"+z(g[1],b)+"|"+z(g[2],c)+"|";d="├"+j+"┼"+k+"┼"+l+"┤";o+=n+d+n;for(int i=1;i<f.Length;i++){var h=f[i].Split(',');o+="|"+z(h[0],a)+"|"+z(h[1],b)+"|"+z(h[2],c)+"|"+n;}d="└"+j+"┴"+k+"┴"+l+"┘";o+=d;return o;}

Ungolfed (e più bello, perché ^ che non serve a nessuno):

public string T(string[] c)
{
  int width = c.Max(r => r.Length),
    longestFirstColumn = c.Select(r => r.Split(',')[0].Length).Max(),
    longestSecondColumn = c.Select(r => r.Split(',')[1].Length).Max(),
    longestThirdColumn = c.Select(r => r.Split(',')[2].Length).Max();

  string o = "", lr = "\r\n", border = "",
    firstColumnFiller = string.Concat(Enumerable.Repeat("─", longestFirstColumn)),
    secondColumnFiller = string.Concat(Enumerable.Repeat("─", longestSecondColumn)),
    thirdColumnFiller = string.Concat(Enumerable.Repeat("─", longestThirdColumn));

  Func<string, int, string> padRight = (a, b) => { return a.PadRight(b); };

  border = "┌" + firstColumnFiller
    + "┬" +
    secondColumnFiller + "┬"
    + thirdColumnFiller
    + "┐";

  o += border + lr;

  var firstRow = c.First().Split(',');

  o += "|" + padRight(firstRow[0], longestFirstColumn) +
    "|" + padRight(firstRow[1], longestSecondColumn) +
    "|" + padRight(firstRow[2], longestThirdColumn) + "|";

  border = "├" +
    firstColumnFiller + "┼" +
    secondColumnFiller + "┼" +
    thirdColumnFiller
    + "┤";

  o += lr + border + lr;

  for (int i = 1; i < c.Length; i++)
  {
    var row = c[i].Split(',');

    o += "|" + padRight(row[0], longestFirstColumn) + "|"
    + padRight(row[1], longestSecondColumn) + "|" +
    padRight(row[2], longestThirdColumn) + "|" + lr;
  }

  border = "└" +
    firstColumnFiller + "┴" +
    secondColumnFiller + "┴" +
    thirdColumnFiller
    + "┘";

  o += border;

  return o;
}

test:

┌──────┬───┬──────┐         ┌──────────┬───────────────────────────┬─────┐
|Name  |Age|Gender|         |Name      |PPCG Challenge             |Votes|
├──────┼───┼──────┤         ├──────────┼───────────────────────────┼─────┤
|Shaun |19 |Male  |         |Pete Arden| Print all integers        | 4   |
|Debra |19 |Female|         |Pete Arden| Yes of course I'm an adult| 3   |
|Alan  |26 |Male  |         |Pete Arden| 5 Favorite Letters        | 1   |
|George|15 |Male  |         └──────────┴───────────────────────────┴─────┘
└──────┴───┴──────┘

In qualche modo, continuo a ottenere 697 byte quando conto questo.
Adám,

@Adám Appena ricontrollato, la stringa Golfed è lunga 666 colonne in Visual Studio. Ma né 666 né 697 sono punteggi esattamente competitivi :)
Pete Arden,

Hai una nuova riga finale, ma anche quando la rimuovi, è ancora 696 byte .
Adám,

@ Adám Ah ... stavo aspettando una discrepanza nel conteggio delle lettere / conteggi byte per farmi inciampare. Avrei dovuto saperlo con questi simboli divertenti in questo ("┼"). Aggiornato, grazie :)
Pete Arden,

Vedi i commenti sopraIs input using list or array of strings (and no newlines) valid? Nope.
edc65,

0

Perl, 273 + 9 ( -CS -nlaF,flag) = 282 byte

$v[$.-1]=[@F];map$l[$_]<($l=length$F[$_])&&($l[$_]=$l),0..$#F}sub p{printf$p,@_}sub o{p
pop,map{$\x$l[$_],$_-$#l?$_[0]:pop}0..$#l}$p=join'%s','',(map"\%-${_}s",@l),$/;($\,$c,@c)=map
chr$_*4+9472,0,.5,3..15;o@c[8,1,0];p($c,map{$_,$c}@$_),$i++||o@c[12,6,4]for@v;o@c[10,3,2];{

usando:

cat file.csv | perl -CS -nlaF, script.pl

Provalo su Ideone .


0

PHP, 313 byte

for(;$r=fgetcsv(STDIN);$a[]=$r)foreach($r as$x=>$s)$e[$x]=max($e[$x],strlen($s));$t=["┬","┌","┐"];eval($L='foreach($e as$i=>$n)echo$t[!$i],str_repeat("─",$n);echo"$t[2]\n";');foreach($a as$k=>$r){foreach($r as$i=>$s)echo"│",str_pad($s,$e[$i]);echo"│\n";$t=["┼","├","┤"];if(!$k)eval($L);}$t=["┴","└","┘"];eval($L);

abbattersi

for(;$r=fgetcsv(STDIN);$a[]=$r)                         // read csv from STDIN, append to array $a
    foreach($r as$x=>$s)$e[$x]=max($e[$x],strlen($s));  // remember max length in array $e
                                                        // print top border
$t=["┬","┌","┐"];eval($L='foreach($e as$i=>$n)echo$t[!$i],str_repeat("─",$n);echo"$t[2]\n";');
foreach($a as$k=>$r)
{
    foreach($r as$i=>$s)echo"│",str_pad($s,$e[$i]);echo"│\n";   // print row
    $t=["┼","├","┤"];if(!$k)eval($L);                           // print border below header
}
$t=["┴","└","┘"];eval($L);                              // print bottom border

Provalo su ideone


0

APL (Dyalog Extended) , 36 25 byte SBCS

Programma completo. Suppone che ABCDEFGHIJKLMNOPQRSTUVWXYZsia il file CSV. Stampa su stdout.

disp(1m)⍪↑¨↓⍉1m←⎕CSVA

Provalo online!

⎕A l' alfabeto A maiuscolo (la stringa incorporata più breve per riferimento)
⎕CSV legge quel file e converte da CSV a
m← archivio matrice poiché m(per m atrix)
1↓ rilascia la prima riga
 trasponi
 suddivisione in elenco di colonne
↑¨ mescola ogni elenco di stringhe in una matrice
(... )⍪ sovrapponi quanto segue:
1↑m prendi la prima riga di m
⌂disp applica dfns.dispa quello (disegna i caratteri del disegno a tratteggio)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.