Implementa "tac": stampa le righe da un file al contrario


30

Tra la domanda sui gattini e vedere questa domanda in U&L su un po 'di sedmagia, che ne dici di implementarla tac?


Obbiettivo

Implementare un programma che inverta e stampa le linee in un file.


Ingresso

Un file, fornito come nome o tramite input standard


Produzione

Le linee, invertite, sono standard.


punteggio

Byte del codice sorgente.


9
tacè un po 'strano quando si tratta di trascinare avanzamenti di riga. Trasforma a\nb\n(avanzamento riga finale) in b\na\ne a\nb(nessun avanzamento riga finale) in ba\n. È così che dovrebbe comportarsi il nostro codice?
Dennis,


10
Inoltre, se dobbiamo replicare il comportamento di tac, una risposta di Bash a 3 byte che viene eseguita tacè solo una questione di tempo ...
Dennis

1
@Dennis a questo punto probabilmente è meglio lasciare indefinito.
Nick T

1
@Dennis ha senso per me. Visualizza le linee di un file come righe orizzontali, tutte che terminano con \n. tacinverte l'ordine di queste righe. Se un \nviene rimosso dalla metà del file, la riga che ha terminato viene unita alla riga successiva, ma nel caso dell'ultima riga, non vi è alcuna riga successiva a cui unirsi.
Blacklight Shining

Risposte:


15

GS2, 3 byte

* +

I tre byte sono, nell'ordine, linee di divisione, linee di inversione e di unione.


9

Perl, 11 byte

$\=$_.$\}{

Si comporta esattamente come tac. Questo codice richiede lo -pswitch, che ho contato come 1 byte.

Esecuzioni di test

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

Come funziona

Come spiegato qui , lo -pswitch sostanzialmente avvolge while (<>) { ... ; print }il programma, quindi il codice sorgente è equivalente

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

Per ogni riga di input, anteponiamo la riga corrente ( $_) a $\(inizialmente non definita), aggiornando quest'ultima con il risultato.

Dopo che tutte le righe sono state elaborate, printstampa il valore della variabile locale $_(non definita in questo ambito), seguita dal separatore del record di output ( $\).


Vuoi spiegare come funziona?
xebtl

2
@xebtl Evilly. L'aggiunta dello -pswitch avvolge il codice in un ciclo che inizia while(<>){e termina } continue { print }, il che consente di filtrare l'input semplicemente modificando $_. $\=$_.$\antepone ciascuna linea di input al terminatore del record di output e }{termina whileprematuramente il blocco fornito dal perl , quindi il continueblocco non è più collegato ad esso. Quindi tutte le righe di input vengono aggiunte $\in ordine inverso, quindi alla fine continue { print }viene eseguito, stampando "niente" ( $_sarà indefinito dopo la fine dell'input), ma con un terminatore di $\.
Hobbs

@xebtl grr, la formattazione del codice nei commenti sembra un po 'rotta in cui barre rovesciate e backtick si avvicinano. Forse puoi indovinare cosa stavo cercando di dire.
Hobbs,

1
@primo Il primo esempio mostra cosa succede in questo caso. L'output sarà strano, ma esattamente come quello di TAC.
Dennis,

1
@Dennis pagine 18 e seguenti di questo libro
msh210,

8

Pyth, 4 byte

j_.z

.zè l'input separato da linee come un elenco, lo _inverte e lo junisce con un carattere, che per impostazione predefinita è \n.



7

Retina , 7 byte

!rm`.*$

Con un unico regex, Retina funziona in modalità Match. Questo normalmente stampa solo il numero di corrispondenze, ma con! noi lo configuriamo per stampare invece le corrispondenze effettive (separate da avanzamenti di riga).

La regex reale è semplicemente .*$. .*corrisponde a qualsiasi riga (potenzialmente vuota), poiché .può corrispondere a qualsiasi carattere tranne gli avanzamenti di riga. Arriverò $tra un minuto.

Come facciamo a stampare le corrispondenze al contrario? Utilizzando la modalità di corrispondenza destra-sinistra di .NET, attivata con r. Ciò significa che il motore regex si avvia alla fine della stringa quando cerca corrispondenze e funziona all'indietro.

Infine, mrende la $corrispondenza la fine di una riga anziché la fine della stringa. Perché ne abbiamo bisogno? Il problema è che .*genera corrispondenze estranee. Considera la sostituzione regex

s/a*/$0x/

applicato all'ingresso baaababaa. Penseresti che questo cederebbe baaaxbaxbaax, ma in realtà ti dà baaaxxbaxxbaaxx. Perché? Perché dopo aver abbinato aaail cursore del motore è tra il ae il b. Ora non può più corrispondere a as, maa* è anche soddisfatto di una stringa vuota. Ciò significa che dopo ogni singola partita ottieni un'altra partita vuota.

Non lo vogliamo qui, perché introdurrebbe ulteriori righe vuote, quindi scartiamo quelle corrispondenze estranee (che sono all'inizio delle righe, a causa della modalità da destra a sinistra) richiedendo che le corrispondenze includano la fine di la linea.


6

Haskell, 34 byte

main=interact$concat.reverse.lines

[modificare]

Salvato un byte sostituendolo unlinescon concat.


4

CJam, 7 byte

qN/W%N*

Legge stdin, stampa su stdout.

Spiegazione:

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


4

Befunge-93, 17 byte

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

Niente di speciale qui; basta mettere tutto in pila, quindi espellerlo.


4

Pure Bash (senza utility esterne), 56

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

Questa è una delle poche risposte per fare l'esatta tacemulazione, come chiesto nel commento di Dennis :

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

Bello e stimolante .
arte


4

JavaScript (SpiderMonkey Shell), 38 byte

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

Abbastanza semplice


read() legge un file

readline() legge una stringa da STDIN

[...str]dividerà str in una matrice di caratteri

reverse() inverte l'array

join`` collocherà l'array in una stringa


4

Python 2, 52 byte

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

1
Input () non legge una riga da stdin?
Lynn,

@Mauris Modificato
Decadimento beta

Che dire import sys;print sys.stdin.read()[::-1]?
Dieter,

@dieter Che inverte ogni personaggio, la sfida richiede solo l'inversione delle linee
Decadimento beta

ok mio male - Non l'ho letto attentamente, scusate
Dieter

4

C #, 179 171 byte

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

Legge le righe, inserendole in una pila e quindi le scrive all'indietro. Userei Mathematica per questo, ma non ha alcun senso dell'EOF.


3

sed, 9 byte

1!G;h;$!d

Nessun voto voluto, questo è un famoso sed one-liner.


10
Se non è il tuo lavoro, ti suggerisco di creare la tua wiki della community di risposta.
lirtosiast


3

Powershell, 41 byte

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

Memorizza il contenuto di un file riga per riga a, inverte ae infine lo stampa.



3

Burlesque , 6 byte

ln<-uN

lndivide linee, <-inverte, uNunisce linee e formati per l'output non elaborato.


3

Bash, 48 43 caratteri

(Ispirato Trauma Digital s' Bash risposta . Upvotes per l'idea dovrebbe andare a lui.)

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

Esecuzione di esempio:

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.

Penso che tu possa fare mapfile -c1 -Cfinvece di mapfile -c1 -Cf a.
Trauma digitale

Corretta. L'ho anche scoperto nel frattempo, ho provato prima qualcosa di così difficile -C.
arte

3

GNU Awk, 27 caratteri

(Ispirato da Ed Morton 's GNU Awk risposta . CW non avevo intenzione di dirottare la sua soluzione.)

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

Notando che cambiando RTRSquesto diventa Awk standard portatile ma perde la capacità di preservare l'assenza della nuova riga finale.

Esecuzione di esempio:

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.

Puoi rimuovere "% s"
ninjalj il

@ninjalj, solo se possiamo supporre che l'input non conterrà mai "%".
arte

3

SNOBOL, 42 byte

S S =INPUT CHAR(10) S :S(S)
 OUTPUT =S
END

2

Gema, 25 personaggi

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

Esecuzione di esempio:

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

sed, 7 byte

G;h;$!d

Questo funziona per me (ed è la soluzione più breve altrove), ma non voglio davvero scoprire perché. Ho appena scherzato con il famoso trucco da 9 byte fino a quando non ho trovato questo. Immagino che Gla prima riga non faccia nulla?


2
In realtà fa qualcosa: il tuo codice produce una nuova riga in più alla fine dell'output. ( Gaccoda una nuova riga e il contenuto dello spazio di attesa allo spazio modello. Mentre aggiungere il contenuto dello spazio di attesa vuoto è davvero innocuo, la nuova riga viene comunque aggiunta.)
manatwork

2

JavaScript (Node.js), 91 byte

console.log(require('fs').readFileSync(process.argv[2])+"".split(d="\n").reverse().join(d))

Intendi console.log((require('fs').readFileSync(process.argv[2])+"").split(d="\n").reverse().join(d))(92 byte)? Il tuo codice attuale non inverte le righe.
Spazzolino da denti

2

Bash + utility comuni, 25

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

Qui ^Gè letteraleBEL personaggio . Suppongo che l'input sia solo ASCII stampabile.

Ciò trrisponde all'intero input su una riga sostituendo le nuove righe con BEL, quindi revsostituisce quella riga, quindi trrisponde nuovamente a più righe, quindi reinserisce nuovamente revogni riga per ottenere l'output desiderato.


2

MATLAB, 44

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

Divide la stringa su nuove linee, inverte l'array risultante, quindi si ricongiunge con nuovi caratteri di linea.


2

Julia, 65 byte

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

Questo prende un file come argomento della riga di comando e stampa le sue linee in ordine inverso. Le nuove righe finali vengono spostate in primo piano, a differenzatac che è legittimo.

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 byte

Utilizza i flag re n; legge da stdin.

RVg

Il rflag legge stdin e lo memorizza come un elenco di righe g(che normalmente è un elenco di ar g della riga di comando ). Quindi invertiamo tale elenco e viene stampato automaticamente. Il nflag fa sì che gli elenchi vengano emessi con newline come separatore.

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.