Numerazione delle linee - attuare nl


13

Il tuo compito è implementare un programma simile allo nlstrumento da riga di comando delle utility GNU core.

Scappatoie standard sono vietate.

Non è possibile utilizzare alcuna funzione, programma o utilità incorporati o esterni per numerare le righe di un file o stringa, come se nlstesso o il= comando in GNU sed.

specificazione

Ingresso

Il programma accetta nomi di file come argomenti. Il tuo codice non deve essere multipiattaforma; deve essere utilizzato il formato del nome file del sistema operativo che esegue il codice, ad esempio se si è in Windows, il separatore di directory può essere \o/ .

Devi essere in grado di prendere 64 file di input, anche -se è specificato. Se ne vengono forniti oltre 64, gestire solo i primi 64.

Nell'elenco dei nomi di file, -rappresenta l'input standard.

Se vengono forniti i nomi dei file, leggi i file nell'ordine in cui sono stati dati e concatena il loro contenuto, inserendo una nuova riga tra ciascuno e alla fine. Se non riesci a leggere da uno o più nomi di file (perché il file non esiste o non disponi delle autorizzazioni di lettura), ignorali. Se tutti i nomi file specificati non sono validi, non generare nulla.

Se non viene fornito alcun nome di file, leggere dall'input standard. Leggere solo dallo standard input se non viene fornito alcun nome file o se -viene fornito.

Produzione

Il programma produrrà, allo standard output, l'input con le righe numerate in questo modo (si può presumere che l'input abbia \n, \r\no \rterminazioni di riga; scegli quale è più conveniente per te, ma specifica quale):

<5 spaces>1<tab><content of line 1 of input>
<5 spaces>2<tab><content of line 2 of input>
...
<4 spaces>10<tab><content of line 10 of input>
...
<3 spaces>100<tab><content of line 100 of input>
...
...

6 caratteri di spazio sono assegnati per il numero di riga e viene inserito alla fine di questi caratteri; il resto diventa spazio (ad es. 1avrà 5 spazi iniziali, 22avrà 4 spazi iniziali, ...). Se l'input è sufficientemente lungo, alla fine si esaurirà lo spazio per il numero di riga 999999. Non è necessario emettere nulla dopo la riga 999999.

Se l'input è vuoto, non viene prodotto nulla.

Stato di uscita

I numeri più bassi hanno la priorità: se si riscontrano errori 1 e 2, uscire con lo stato 1.

Esci con lo stato 0 se l'ingresso è stato ricevuto correttamente e le righe sono state numerate e emesse correttamente.

Esci con lo stato 1 se uno o più file specificati nella riga di comando non sono stati trovati o non è stato possibile leggere.

Esci con lo stato 2 se sono stati dati troppi file (più di 64).

Esci con lo stato 3 se l'ingresso era troppo lungo (più di 999999 righe). \

punteggio

Questo è code-golf - il programma più corto vince!

Potrei aggiungere bonus in seguito per l'implementazione di alcune opzioni che nlha. Non ci sono bonus al momento.


La numerazione delle righe è continua o breve "reimpostata" per ogni singolo file?
britishtea,

@britishtea È continuo

1
Quindi è necessario usare il nodo se vogliamo inviare qualcosa in js? Oppure possiamo usare args di funzione o prompt()emulare args di programma e stdin?
DankMemes,

1
File binari? Codifica? Marcatori Unicode?
edc65,

Risposte:


6

Bash, 121

s=$[2*($#>64)]
for f in "$@";{ [ -f $f ]||s=1;}
((s))&&exit $s
awk '{if(NR>=10**6){exit 3}printf("%6d\t%s\n",NR,$0)}' $@

1
Puoi rendere le tue ifespressioni un po 'più brevi se usi espressioni aritmetiche, ad esempio(($#>64))&&s=2
Digital Trauma,

2
@DigitalTrauma Ho imparato una cosa!
Sammitch,

1
È possibile sostituire s=0;(($#>64))&&s=2con s=$[2*($#>64)], (($s==0))||con ((s))&&e la ifdichiarazione con [ -f "$f" ]||s=1.
Dennis,


2
awkconcatenerà anche se vengono passati più file, quindi questo conta ufficialmente come un uso inutile di cat ;-). Invece penso che funzionerà:awk '...' $@
Digital Trauma,

2

Ruby, 195

o,l=$*[64]?[2]:[],999999
($*==[]?[?-]:$*).each{|n|f=n==?-?STDIN: open(n)rescue o<<1&&next
s=f.read.lines
s[l]?o<<3:1
puts s[0..l].map.with_index(1){|l,i|i.to_s.rjust(6)+?\t+l}}
exit !o[0]?0:o.min

Penso che STDINsia aliasato $<.
Martin Ender,

È un alias per ARGF, che leggerà anche dal resto dei file forniti come argomenti. Penso che questo possa essere ulteriormente approfondito usando in ARGFqualche modo (sembra persino riconoscere "-"come stdin).
britishtea,

britishteanl: 4: in block in <main>': undefined method [] 'per # <Enumeratore: 0x000006002980c8> (NoMethodError) da britishteanl: 2: in each' from britishteanl:2:in <main>' - cosa c'è che non va? L'ho eseguito comeruby britishteanl folder/filename

Sospetto che sia una differenza nella versione di Ruby. Ho eseguito l'esempio su Ruby 2.0.0 e Ruby 2.1.2 senza problemi. Quale versione stai usando?
britishtea,

2

Perl, 84 + 2 ( -pl) = 86 byte

perl -ple'BEGIN{map{-r||exit 1}@ARGV;@ARGV>63&&exit 2}$.>=1e6&&exit 3;$_=printf"%5d\t%s",$.,$_'

Deparsed:

perl -MO=Deparse -ple'BEGIN{map{-r||exit 1}@ARGV;@ARGV>63&&exit 2}$.>=1e6&&exit 3;$_=printf"%5d\t%s",$.,$_' output.txt; echo $?

BEGIN { $/ = "\n"; $\ = "\n"; }
sub BEGIN {
    map {exit 1 unless -r $_;} @ARGV;
    exit 2 if @ARGV > 63;
}
LINE: while (defined($_ = <ARGV>)) {
    chomp $_;
    exit 3 if $. >= 1000000;
    $_ = printf("%5d\t%s", $., $_);
}
continue {
    die "-p destination: $!\n" unless print $_;
}
-e syntax OK

Importante sapere:

  • -pavvolge il programma indicato con -enel while/ continueloop
  • BEGIN il codice verrà eseguito prima della parte principale (implicita)
  • il test dei file -rfallisce anche se il file non esiste !-ee per impostazione predefinita è il test $_, implicitamente indicatomap { ... } @ARGV
  • $. contiene il numero di riga corrente
  • il resto dovrebbe essere autoesplicativo;)

Ottima risposta, e benvenuti a Puzzle di programmazione e Code Golf! Forse potresti modificare per aggiungere una spiegazione di come funziona il tuo codice.
wizzwizz4,

1

pitone 173

import os,sys
c=0
l=1
for f in sys.argv[1:]:
    if c>64:exit(2)
    if not os.path.isfile(f):exit(1)
    c+=1
    for x in open(f):
        if l>=10**6:exit(3)
        print '%6d\t%s'%(l,x),;l+=1

Penso che al tuo codice al momento manchi il -per sys.stdin. Una possibile soluzione potrebbe essere qualcosa di simile fh=sys.stdin if f=='-' else open(f)e poi andare avanti x=fh.readline()?! Purtroppo però non lo rende più breve. :)
Dave J,

1

J (162)

exit(((2*64<#)[exit@3:`(stdout@(,&LF)@;@(,&TAB@(6&":)&.>@>:@i.@#,&.>]))@.(1e6>#)@(<;.2)@(1!:1)@(<`3:@.('-'-:]))&.>@;@{.@(_64&(<\))) ::1:)]`(]&<&'-')@.(0=#)2}.ARGV

Spiegazione:

  • ]`(]&<&'-')@.(0=#)2}.ARGV: Ottieni gli argomenti della riga di comando e rimuovi i primi due (perché quelli sono l'interprete e il nome del file di script). Se l'elenco risultante è vuoto, restituire ['-'](ovvero, come se solo l'utente fosse passato -), altrimenti restituire l'elenco invariato.
  • (... ::1:): se la funzione interna fallisce, ritorna 1, altrimenti restituisce qualunque sia la funzione interna restituita.
  • ((2*64<#)[... ): valuta la funzione interna e getta via il risultato. Quindi, se la lunghezza dell'elenco passato non era superiore a 64, ritorna 0, altrimenti ritorna 2.
  • &.>@;@{.@(_64&(<\)): ottiene al massimo 64elementi dall'elenco e per ognuno di essi esegue la seguente funzione:
    • (1!:1)@(<`3:@.('-'-:])): se l'elemento era -, leggi il contenuto del descrittore di file 3(stdin), altrimenti leggi il contenuto del file chiamato da quell'elemento. Se fallisce (cioè il file non esiste), il codice sopra lo prenderà e tornerà 1.
    • exit@3:`(... )@.(1e6>#)@(<;.2): dividere la stringa sui suoi finali. Se ci sono 1.000.000 o più righe, uscire con lo stato 3. Altrimenti:
      • ,&TAB@(6&":)&.>@>:@i.@#: genera i numeri per ogni riga, formattali in una colonna di 6 cifre e aggiungi TABa alla fine di ogni stringa,
      • ,&.>]: aggiungi ciascun numero all'inizio di ogni riga.
      • stdout@(,&LF)@;: quindi emette il tutto, seguito da un extra LF.
  • exit: esci con il valore di ritorno di quella funzione

1

Rubino, 76 byte

Un byte per la pbandiera. Corri con ruby -p nl.rb.

BEGIN{x=$*.size-65}
exit 2if$*.size==x
exit 3if$.>999999
$_="%6d"%$.+?\t+$_

gli argomenti stdin o file sono gestiti automaticamente da Ruby. Esce già con il codice 1 se non esiste un argomento file. $.è il numero di righe che sono state lette. $*sono gli argomenti della riga di comando e i file vengono estratti mentre vengono letti. Il pflag esegue il BEGINblocco e avvolge il resto del programma in un ciclo while-gets-print, usando $_come input / output.


La specifica dice che dovresti gestire i primi 64 input se dati più di 64, piuttosto che rinunciare all'inizio.
Anders Kaseorg,

@AndersKaseorg fixed.
daniero,

1

Perl, 125 122 byte

@a=@ARGV;for(@a){$i++>63&&exit 2;($_ eq '-'or-e$_)or next;@ARGV=$_;while(<>){$c>1E6-2&&exit 3;printf"%5d\t%s",++$c,$_}say}

Ciò non soddisfa le specifiche relative al massimo 64 argomenti e allo stato di uscita.
Anders Kaseorg,

@AndersKaseorg Fixed!
Gowtham,

0

C, 362 359

Solo per divertimento. ;-) Funziona con avanzamenti di linea LF o CR / LF.

#include<stdio.h>
#define R return
#define P printf(
e,t,l;void*f;r(){P"% 6d\t",++l);for(;(t=fgetc(f))^-1&&l<1000000;){if(ferror(f))R 1;P"%c",t);if(t==10)P"% 6d\t",++l);}P"\n");R l<1000000?0:3;}main(int c,char**v){e=c>65?2:0;for(++v;*v||c<2;++v){t=c<2||!strcmp(*v,"-")?f=stdin,0:!(f=fopen(*v,"rb"));if(t||(t=r()))e=!e|(e>t)?t:e;if(f&&f!=stdin)fclose(f);}R e;}
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.