Zeilennummerierung - Implementiere nl


13

Ihre Aufgabe ist es, ein Programm zu implementieren, das dem nlBefehlszeilentool der GNU-Kerndienstprogramme ähnelt .

Standardlücken sind verboten.

Sie dürfen keine eingebauten oder externen Funktionen, Programme oder Hilfsprogramme zum Nummerieren der Zeilen einer Datei oder eines Strings verwenden, wie z. B. sich nlselbst oder den =Befehl in GNU sed.

Spezifikation

Eingang

Das Programm akzeptiert Dateinamen als Argumente. Ihr Code muss nicht plattformübergreifend sein. Das Dateinamenformat des Betriebssystems, auf dem der Code ausgeführt wird, sollte verwendet werden. Wenn Sie sich also unter Windows befinden, kann das Verzeichnistrennzeichen \oder sein /.

Sie müssen in der Lage sein, 64 Eingabedateien aufzunehmen, auch -wenn diese angegeben sind. Wenn mehr als 64 angegeben sind, behandeln Sie nur die ersten 64.

Stellt in der Liste der Dateinamen -die Standardeingabe dar.

Wenn Dateinamen angegeben werden, lesen Sie diese in der angegebenen Reihenfolge aus und verketten Sie ihren Inhalt, indem Sie jeweils eine neue Zeile zwischen und am Ende einfügen. Wenn Sie einen oder mehrere Dateinamen nicht lesen können (weil die Datei nicht vorhanden ist oder Sie keine Leseberechtigung dafür haben), ignorieren Sie sie. Wenn alle angegebenen Dateinamen ungültig sind, wird nichts ausgegeben.

Wenn keine Dateinamen angegeben sind, lesen Sie von der Standardeingabe. Lesen Sie von der Standardeingabe nur, wenn keine Dateinamen angegeben sind oder wenn -angegeben.

Ausgabe

Das Programm wird ausgegeben, auf der Standardausgabe, die Eingabe mit Linien so nummeriert (Sie gehen davon aus , dass der Eingang hat \n, \r\noder \rZeilenende, wählen je nachdem , was für Sie bequem ist, aber angeben , welche):

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

Die Zeilennummer wird mit 6 Leerzeichen versehen und am Ende dieser Zeichen eingefügt. Der Rest wird zu Leerzeichen (z. B. 15 führende Leerzeichen, 224 führende Leerzeichen, ...). Wenn die Eingabe ausreichend lang ist, ist möglicherweise nicht mehr genügend Platz für die Zeilennummer in Zeile vorhanden 999999. Sie dürfen nach Zeile 999999 nichts mehr ausgeben.

Wenn die Eingabe leer ist, wird nichts ausgegeben.

Beenden Sie den Status

Die niedrigeren Zahlen haben Vorrang: Wenn Fehler 1 und 2 aufgetreten sind, beenden Sie mit Status 1.

Beenden Sie mit dem Status 0, wenn die Eingabe erfolgreich empfangen und die Zeilen erfolgreich nummeriert und ausgegeben wurden.

Beenden Sie mit Status 1, wenn eine oder mehrere der in der Befehlszeile angegebenen Dateien nicht gefunden wurden oder nicht gelesen werden konnten.

Beenden Sie mit Status 2, wenn zu viele Dateien (mehr als 64) angegeben wurden.

Beenden Sie mit Status 3, wenn die Eingabe zu lang war (mehr als 999999 Zeilen). \

Wertung

Das ist Code-Golf - das kürzeste Programm gewinnt!

Ich kann später Boni für die Implementierung bestimmter Optionen hinzufügen, die nlhat. Im Moment gibt es keine Boni.


Ist die Zeilennummerierung durchgehend oder wird sie für jede einzelne Datei von selbst "zurückgesetzt"?
Britishtea

@britishtea Es ist kontinuierlich

1
Ist es also notwendig, node zu verwenden, um etwas in js einzureichen? Oder können wir Funktionsargumente verwenden oder prompt()Programmargumente und stdin emulieren?
DankMemes

1
Binärdateien? Codierung? Unicode-Marker?
Edc65

Antworten:


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
Sie können Ihre ifAusdrücke etwas kürzer machen, wenn Sie arithmetische Ausdrücke verwenden, z. B.(($#>64))&&s=2
Digitales Trauma

2
@DigitalTrauma Ich habe etwas gelernt!
Sammitch

1
Sie können s=0;(($#>64))&&s=2mit s=$[2*($#>64)], (($s==0))||mit ((s))&&und die ifAnweisung mit ersetzen [ -f "$f" ]||s=1.
Dennis


2
awkWird auch verkettet, wenn mehrere Dateien übergeben werden, so gilt dies offiziell als nutzlose Verwendung von cat ;-). Stattdessen denke ich, dass dies funktionieren wird:awk '...' $@
Digitales Trauma

2

Rubin, 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

Ich denke, STDINist voreingenommen $<.
Martin Ender

Es ist ein Alias ​​für ARGF, der auch aus den übrigen als Argumente angegebenen Dateien liest. Ich denke, das kann man irgendwie weiter mit Golf spielen ARGF(es scheint sogar als Standard zu gelten "-").
Britishtea

britishteanl: 4: in block in <main>': undefined method [] 'für # <Enumerator: 0x000006002980c8> (NoMethodError) von britishteanl: 2: in each' from britishteanl:2:in <main>' - was ist falsch? Ich lief es alsruby britishteanl folder/filename

Ich vermute, es ist ein Unterschied in der Ruby-Version. Ich habe das Beispiel sowohl auf Ruby 2.0.0 als auch auf Ruby 2.1.2 ohne Probleme ausgeführt. Welche Version benutzt du?
britishtea

2

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

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

Wichtig zu wissen:

  • -p bricht das angegebene Programm mit -e in die while/ continueSchleife ein
  • BEGIN Code wird vor dem (impliziten) Hauptteil ausgeführt
  • Der Dateitest -rschlägt auch fehl, wenn die Datei nicht vorhanden ist!-e$_ Standardwert ist testing , implizit angegeben inmap { ... } @ARGV
  • $. Enthält die aktuelle Zeilennummer
  • Rest sollte selbsterklärend sein;)

Tolle Antwort und willkommen bei Programming Puzzles und Code Golf! Vielleicht könnten Sie eine Erklärung hinzufügen, wie Ihr Code funktioniert.
wizzwizz4

1

Python 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

Ich denke, Ihr Code fehlt derzeit die -für sys.stdin. Eine mögliche Lösung könnte so etwas sein fh=sys.stdin if f=='-' else open(f)und dann mitgehen x=fh.readline()?! Leider wird es dadurch nicht kürzer. :)
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

Erläuterung:

  • ]`(]&<&'-')@.(0=#)2}.ARGV: Rufen Sie die Befehlszeilenargumente ab und entfernen Sie die ersten beiden (da dies der Interpreter und der Name der Skriptdatei sind). Wenn die resultierende Liste leer ist, geben Sie zurück ['-'](dh als ob der Benutzer nur bestanden hätte -), andernfalls geben Sie die Liste unverändert zurück.
  • (... ::1:): Wenn die innere Funktion fehlschlägt, kehren Sie zurück 1, andernfalls kehren Sie zurück, was auch immer die innere Funktion zurückgegeben hat.
  • ((2*64<#)[... ): die innere Funktion bewerten und das Ergebnis wegwerfen. Wenn dann die Länge der übergebenen Liste nicht größer als war 64, kehren Sie zurück 0, andernfalls kehren Sie zurück 2.
  • &.>@;@{.@(_64&(<\)): Hole höchstens 64Elemente aus der Liste und führe für jedes die folgende Funktion aus:
    • (1!:1)@(<`3:@.('-'-:])): Wenn das Element war -, lesen Sie den Inhalt des Dateideskriptors 3(stdin), andernfalls lesen Sie den Inhalt der Datei, die von diesem Element benannt wurde. Wenn dies fehlschlägt (dh die Datei existiert nicht), wird sie vom obigen Code abgefangen und zurückgegeben1 .
    • exit@3:`(... )@.(1e6>#)@(<;.2): Teilen Sie die Zeichenfolge an den Zeilenenden. Wenn es 1.000.000 oder mehr Zeilen gibt, beenden Sie mit dem Status 3. Andernfalls:
      • ,&TAB@(6&":)&.>@>:@i.@#: Generieren Sie die Zahlen für jede Zeile, formatieren Sie sie in einer 6-stelligen Spalte und fügen Sie a hinzu TAB am Ende jeder Zeichenfolge ein hinzu.
      • ,&.>]: füge jede Zahl vor jeder Zeile hinzu.
      • stdout@(,&LF)@;: dann das Ganze ausgeben, gefolgt von einem Extra LF.
  • exit: exit mit dem Rückgabewert dieser Funktion

1

Ruby, 76 Bytes

Ein Byte für die pFlagge. Laufen Sie mit ruby -p nl.rb.

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

Standard- oder Dateiargumente werden automatisch von Ruby behandelt. Es wird bereits mit Code 1 beendet, wenn kein Dateiargument vorhanden ist. $.ist die Anzahl der gelesenen Zeilen. $*sind die Befehlszeilenargumente, und die Dateien werden beim Lesen entfernt. Das pFlag führt den BEGINBlock aus und schließt den Rest des Programms in eine while-gets-print-Schleife ein, wobei es $_als Ein- / Ausgabe verwendet wird.


Die Spezifikation besagt, dass Sie die ersten 64 Eingaben behandeln sollten, wenn mehr als 64 eingegeben wurden, anstatt nur am Anfang aufzugeben.
Anders Kaseorg

@AndersKaseorg behoben.
Daniero

1

Perl, 125 122 Bytes

@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}

Dies entspricht nicht der Spezifikation bezüglich des 64-Argument-Maximums und des Exit-Status.
Anders Kaseorg

@AndersKaseorg behoben!
Gowtham

0

C 362 359

Einfach nur so. ;-) Funktioniert mit LF- oder CR / LF-Zeilenvorschüben.

#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;}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.