Implementieren Sie "tac": Drucken Sie Zeilen aus einer Datei in umgekehrter Reihenfolge

30

Zwischen der Kätzchenfrage und der Frage bei U & L nach etwas sedMagie, wie wäre es mit der Implementierung tac?


Zielsetzung

Implementieren Sie ein Programm, das die Zeilen in einer Datei umkehrt und druckt.


Eingang

Eine Datei, die als Name oder über die Standardeingabe bereitgestellt wird


Ausgabe

Die Linien sind vertauscht, um zu standardisieren.


Wertung

Bytes des Quellcodes.

Nick T
quelle
9
tacist etwas seltsam, wenn es um nachgestellte Zeilenvorschübe geht. Es wandelt sich in a\nb\n(Trailing Linefeed) b\na\nund in a\nb(No Trailing Linefeed) um ba\n. Soll sich unser Code so verhalten?
Dennis
Related
Martin Ender
10
Auch wenn wir das Verhalten von tac replizieren müssen, ist eine 3-Byte-Bash-Antwort, die ausgeführt tacwird, nur eine Frage der Zeit ...
Dennis
1
@Dennis an dieser Stelle wohl am besten undefiniert lassen.
Nick T
1
@ Tennis Macht Sinn für mich. Visualisieren Sie die Zeilen einer Datei als horizontale Zeilen, die alle mit enden \n. tackehrt die Reihenfolge dieser Zeilen um. Wenn ein \naus der Mitte der Datei entfernt wird, wird die abgeschlossene Zeile mit der nächsten Zeile verbunden. Bei der letzten Zeile gibt es jedoch keine nächste Zeile, zu der eine Verbindung hergestellt werden kann.
Blacklight Shining

Antworten:

15

GS2, 3 Bytes

* +

Die drei Bytes sind in der Reihenfolge geteilte Zeilen, umgekehrte Zeilen und Verbindungszeilen.

rekursiv
quelle
9

Perl, 11 Bytes

$\=$_.$\}{

Benimmt sich genau so tac. Dieser Code erfordert den -pSchalter, den ich als 1 Byte gezählt habe.

Testläufe

$ echo -en 'a\nb' | perl -pe'$\=$_.$\}{' | xxd -g 1
0000000: 62 61 0a                                         ba.
$ echo -en 'a\nb\n' | perl -pe'$\=$_.$\}{' | xxd -g 1
0000000: 62 0a 61 0a                                      b.a.

Wie es funktioniert

Wie hier erklärt , -pumschließt der Schalter while (<>) { ... ; print }das Programm im Grunde genommen , sodass der Quellcode äquivalent zu ist

 while(<>)
 {
   $\ = $_ . $\
 }
 print

Für jede Eingabezeile stellen wir die aktuelle Zeile voran ($_ ) vor $\(anfangs undefiniert) und aktualisieren letztere mit dem Ergebnis.

Nachdem alle Zeilen verarbeitet wurden, wird printder Wert der lokalen Variablen $_(in diesem Bereich nicht definiert) gefolgt vom Trennzeichen für Ausgabedatensätze ( $\) gedruckt .

Dennis
quelle
Möchtest du erklären, wie das funktioniert?
Xebtl
2
@xebtl Evilly. Durch das Hinzufügen des -pSchalters wird der Code in eine Schleife eingeschlossen, die beginnt while(<>){und endet } continue { print }, sodass Eingaben nur durch Ändern gefiltert werden können $_. $\=$_.$\stellt jede Eingabezeile vor den Abschluss des Ausgabedatensatzes und }{beendet den von Perl bereitgestellten whileBlock vorzeitig, sodass der continueBlock nicht mehr an ihn angehängt wird. Alle Eingabezeilen werden also $\in umgekehrter Reihenfolge hinzugefügt. Am Ende wird continue { print }schließlich "nothing" ( $_wird nach dem Ende der Eingabe undef sein) ausgegeben, jedoch mit einem Abschlusszeichen von $\.
Hobbs
@xebtl grr, die Code-Formatierung in Kommentaren scheint ein bisschen kaputt zu sein, wenn Backslashes und Backticks nahe beieinander liegen. Vielleicht können Sie erraten, was ich sagen wollte.
Hobbs
1
@primo Das erste Beispiel zeigt, was in diesem Fall passiert. Die Ausgabe wird seltsam sein, aber genau wie bei TACs.
Dennis
1
@Dennis Seite 18 ff. Dieses Buches
msh210
8

Pyth, 4 Bytes

j_.z

.zIst die Eingabe durch Zeilen getrennt als Liste, _kehrt sie um und jverbindet sie mit einem Zeichen, was standardmäßig so ist \n.

orlp
quelle
8

FlogScript , 2 Bytes

)"

(Versuchen Sie es auf Anarchie Golf .)

Der )Aktivierungsmodus --in-out-line-arrayund der Rest des Programms ist das "Umkehren des Zeilenarrays.

Lynn
quelle
Argh, du hast mich geschlagen!
mbomb007
7

Retina , 7 Bytes

!rm`.*$

Mit einem einzigen regulären Ausdruck wird Retina im Match-Modus ausgeführt. Dies gibt normalerweise nur die Anzahl der Übereinstimmungen aus, aber mit! wir konfigurieren es stattdessen so, dass die tatsächlichen Übereinstimmungen gedruckt werden (durch Zeilenvorschübe getrennt).

Der eigentliche reguläre Ausdruck ist lediglich .*$. .*Stimmt mit jeder Zeile überein (möglicherweise leer), da .sie mit jedem Zeichen außer Zeilenvorschub übereinstimmen kann. Ich komme zum$ .

Wie bringen wir es dazu, die Übereinstimmungen in umgekehrter Reihenfolge auszudrucken? Verwenden Sie den von rechts nach links abgleichenden Modus von .NET, der mit aktiviert wirdr . Dies bedeutet, dass die Regex-Engine bei der Suche nach Übereinstimmungen am Ende der Zeichenfolge startet und rückwärts arbeitet.

Schließlich mwird die $Übereinstimmung mit dem Ende einer Zeile anstelle des Endes der Zeichenfolge hergestellt. Warum brauchen wir das überhaupt? Das Problem ist, dass .*irrelevante Übereinstimmungen entstehen. Betrachten Sie die Regex-Substitution

s/a*/$0x/

auf den Eingang angewendet baaababaa. Sie würden denken, dies würde nachgeben baaaxbaxbaax, aber es gibt Ihnen tatsächlich baaaxxbaxxbaaxx. Warum? Denn nach dem Abgleichen befindet sich aaader Cursor des Motors zwischen dem aund dem b. Jetzt kann es nicht mehr mit as übereinstimmen , sondern a*ist auch mit einem leeren String zufrieden. Dies bedeutet, dass Sie nach jedem einzelnen Spiel ein weiteres leeres Spiel erhalten.

Wir wollen das hier nicht, weil es zusätzliche Leerzeilen einführen würde, also verwerfen wir diese irrelevanten Übereinstimmungen (die aufgrund des Modus von rechts nach links am Anfang der Zeilen stehen), indem wir verlangen, dass Übereinstimmungen das Ende von enthalten die Linie.

Martin Ender
quelle
6

Haskell, 34 Bytes

main=interact$concat.reverse.lines

[bearbeiten]

Gespeichert ein Byte durch den Ersatz unlinesmit concat.

jkabrg
quelle
4

CJam, 7 Bytes

qN/W%N*

Liest stdin, druckt nach stdout.

Erläuterung:

q       Get input.
N/      Split at newlines.
W%      Reverse list.
N*      Join with newlines.
Reto Koradi
quelle
4

Befunge-93, 17 Bytes

~:1+!#v_
>:#,_@>$

Nichts Besonderes hier; lege einfach alles auf den Stapel und lege es dann ab.

Kevin W.
quelle
4

Pure Bash (keine externen Dienstprogramme), 56

mapfile a
for((i=${#a[@]};i--;));{
printf %s "${a[i]}"
}

Dies ist eine der wenigen Antworten, um eine exakte tacEmulation durchzuführen, wie in Dennis 'Kommentar gefragt :

$ echo -en 'a\nb' | ./tacemu.sh | xxd -g 1
0000000: 62 61 0a                                         ba.
$ echo -en 'a\nb\n' | ./tacemu.sh | xxd -g 1
0000000: 62 0a 61 0a                                      b.a.
$ 
Digitales Trauma
quelle
Schön und inspirierend .
Manatwork
4

Ruby, 16 Bytes

puts [*$<].reverse
daniero
quelle
4

JavaScript (SpiderMonkey-Shell), 38 Byte

[...read(readline())].reverse().join``

Ziemlich einfach


read() liest eine Datei

readline() liest einen String aus STDIN

[...str]wird str in eine Reihe von Zeichen aufteilen

reverse() kehrt das Array um

join`` wird das Array in eine Zeichenkette zusammenfassen

Downgoat
quelle
4

Python 2, 52 Bytes

import sys;print''.join(sys.stdin.readlines()[::-1])
Beta-Zerfall
quelle
1
Liest input () nicht eine Zeile von stdin?
Lynn
@ Mauris Bearbeitet
Beta-Zerfall
Was ist import sys;print sys.stdin.read()[::-1]?
Dieter
@ Dieter Das kehrt jeden Charakter um, die Herausforderung verlangt, dass nur die Zeilen umgedreht werden
Beta Decay
ok my bad - habe es nicht sorgfältig gelesen, sorry
Dieter
4

C # 179 171 Bytes

using B=System.Console;class A{static void Main(){var a=new System.Collections.Stack();string b;while((b=B.ReadLine())!=null)a.Push(b);foreach(var c in a)B.WriteLine(c);}}

Liest Zeilen, legt sie in einen Stapel und schreibt sie dann rückwärts. Ich würde dafür Mathematica verwenden, aber es hat keinen Sinn für EOF.

LegionMammal978
quelle
3

sed, 9 bytes

1!G;h;$!d

Keine Gegenstimme erwünscht, dies ist ein berühmter sed Einzeiler.

Steve
quelle
10
Wenn es nicht deine eigene Arbeit ist, schlage ich vor, dein Antwort-Community-Wiki zu erstellen.
Lirtosiast
3

Perl, 16 Bytes

print reverse<>
Steve
quelle
@ Tennis oops, jetzt zurückgesetzt.
Steve
3

Powershell, 41 Bytes

$a=$args|%{gc $_};[array]::Reverse($a);$a

Speichert den Inhalt einer Datei zeilenweise a, kehrt ihn um aund druckt ihn schließlich aus.

Süßkartoffel
quelle
3

GolfScript, 7 Bytes

n/-1%n*

Online Test hier .

Cristian Lupascu
quelle
3

Burlesque , 6 Bytes

ln<-uN

lnTeilt Linien, <-kehrt sie um, uNfügt Linien und Formate für die Rohausgabe zusammen.

Lynn
quelle
3

Bash, 48 43 Zeichen

(Inspiriert von Digital - Trauma ‚s Bash Antwort . Upvotes für die Idee zu ihm gehen soll.)

mapfile -c1 -C's=$2$s;set'
printf %s "$2$s"

Probelauf:

bash-4.3$ echo -en 'a\nb' | bash tac.sh | xxd -g 1
0000000: 62 61 0a                                         ba.

bash-4.3$ echo -en 'a\nb\n' | bash tac.sh | xxd -g 1
0000000: 62 0a 61 0a                                      b.a.
Mann bei der Arbeit
quelle
Ich glaube , Sie können tun , mapfile -c1 -Cfstatt mapfile -c1 -Cf a.
Digital Trauma
Richtig. Ich habe es auch in der Zwischenzeit entdeckt, habe erst einmal versucht, dieses heikle Thema zu umgehen -C.
Manatwork
3

GNU Awk, 27 Zeichen

(Inspiriert von Ed Morton ‚s GNU Awk Antwort . CW , da ich nicht seine Lösung kapern gedacht.)

{s=$0RT s}END{printf"%s",s}

Beachten Sie dies, indem Sie RT→ ändernRS dies zum portablen Standard-Awk wird, jedoch die Fähigkeit verloren geht, das Fehlen des letzten Zeilenumbruchs beizubehalten.

Probelauf:

bash-4.3$ echo -en 'a\nb' | awk '{s=$0RT s}END{printf"%s",s}' | xxd -g 1
0000000: 62 61 0a                                         ba.

bash-4.3$ echo -en 'a\nb\n' | awk '{s=$0RT s}END{printf"%s",s}' | xxd -g 1
0000000: 62 0a 61 0a                                      b.a.
Handarbeit
quelle
Sie können die „% s“ entfernen
ninjalj
@ninjalj, nur wenn wir davon ausgehen können, dass die Eingabe niemals "%" enthält.
Manatwork
3

SNOBOL, 42 Bytes

S S =INPUT CHAR(10) S :S(S)
 OUTPUT =S
END
Ninjalj
quelle
2

Gema, 25 Zeichen

*\n=@set{s;$0${s;}}
\Z=$s

Probelauf:

bash-4.3$ echo -en 'a\nb' | gema '*\n=@set{s;$0${s;}};\Z=$s'
ba

bash-4.3$ echo -en 'a\nb\n' | gema '*\n=@set{s;$0${s;}};\Z=$s'
b
a
Mann bei der Arbeit
quelle
2

Hassium , 90 Bytes 86 Bytes

use IO;func main(){c=File.readLines(args[0]);for(x=c.length-1;x>=0; println(c[x--]))0;

Siehe hier erweitert

Jacob Misirian
quelle
1
Ich kann dies sehr verkürzen, indem man die forSyntax missbraucht . Sehen Sie eine Probe hier
FryAmTheEggman
Guter Anruf @FryAmTheEggman! Ich habe es hinzugefügt.
Jacob Misirian
2

sed, 7 bytes

G;h;$!d

Dies funktioniert für mich (und es ist die kürzeste Lösung an anderer Stelle), aber ich möchte nicht wirklich herausfinden, warum. Ich habe nur mit dem berühmten 9-Byte-Trick rumgespielt, bis ich ihn gefunden habe. Ich vermute, Gdie erste Zeile macht nichts?

Lynn
quelle
2
Tatsächlich bewirkt Ihr Code am Ende der Ausgabe einen zusätzlichen Zeilenumbruch. ( GFügt eine neue Zeile und den Inhalt des Haltebereichs an den Musterbereich an. Während das Anhängen des Inhalts des leeren Haltebereichs in der Tat harmlos ist, wird die neue Zeile immer noch angehängt.)
Manatwork
2

JavaScript (Node.js), 91 Bytes

console.log(require('fs').readFileSync(process.argv[2])+"".split(d="\n").reverse().join(d))
Ben Fortune
quelle
Meinten Sie console.log((require('fs').readFileSync(process.argv[2])+"").split(d="\n").reverse().join(d))(92 bytes)? Ihr aktueller Code kehrt die Zeilen nicht um.
Zahnbürste
2

Bash + gemeinsame Dienstprogramme, 25

tr \\n ^G|rev|tr ^G \\n|rev

Hier ^Gist das ein wörtlichesBEL Buchstabe. Ich gehe davon aus, dass die Eingabe nur als ASCII druckbar ist.

Dadurch trwird die gesamte Eingabe in eine Zeile umgewandelt, indem neue Zeilen durch BELs ersetzt werden. Anschließend revwird diese Zeile ersetzt. Anschließend wird die trEingabe in revmehrere Zeilen umgewandelt und jede Zeile erneut ersetzt, um die gewünschte Ausgabe zu erhalten.

Digitales Trauma
quelle
2

MATLAB, 44

@(x) strjoin(fliplr(strsplit(x,'\n')),'\n');

Teilt die Zeichenfolge in neue Zeilen, dreht das resultierende Array um und fügt dann neue Zeilenzeichen hinzu.

Tom Carpenter
quelle
2

Julia, 65 Bytes

open(s->print(join(reverse([l for l=readlines(s)]),"")),ARGS[1])

Dabei wird eine Datei als Befehlszeilenargument verwendet und die Zeilen in umgekehrter Reihenfolge gedruckt. Nachfolgende Zeilenumbrüche werden im Gegensatz dazu nach vorne verschobentac , was legitim ist.

Ungolfed:

function p(s::Stream)
    # Create a vector of the lines of the input stream
    L = [l for l in readlines(s)]

    # Reverse the vector and join it back into a string
    j = join(reverse(L), "")

    # Print the string to STDOUT
    print(j)
end

# Open the file specified in the first command line argument
# and apply the function p to its contents
open(p, ARGS[1])
Alex A.
quelle
2

Pip , 3 + 2 = 5 Bytes

Verwendet die rund nFlags; liest aus stdin.

RVg

Das rFlag liest stdin und speichert es als Liste von Zeilen in g(was normalerweise eine Liste von Befehlszeilen-Ar g en ist). Wir kehren diese Liste dann um und sie wird automatisch gedruckt. Das nFlag bewirkt, dass Listen mit Zeilenvorschub als Trennzeichen ausgegeben werden.

DLosc
quelle