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.


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


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.


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 .


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.


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.


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.


6

Haskell, 34 Bytes

main=interact$concat.reverse.lines

[bearbeiten]

Gespeichert ein Byte durch den Ersatz unlinesmit concat.


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.


4

Befunge-93, 17 Bytes

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

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


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

Schön und inspirierend .
Manatwork


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


4

Python 2, 52 Bytes

import sys;print''.join(sys.stdin.readlines()[::-1])

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.


3

sed, 9 bytes

1!G;h;$!d

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


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


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.



3

Burlesque , 6 Bytes

ln<-uN

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


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.

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.

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

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

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


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?


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

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.


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.


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])

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.

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.