Implementar "tac": imprimir líneas de un archivo en reversa

30

Entre la pregunta del gatito y ver esta pregunta en U&L sobre algo de sedmagia, ¿qué hay de implementar tac?


Objetivo

Implemente un programa que invierta e imprima las líneas en un archivo.


Entrada

Un archivo, proporcionado como nombre o mediante entrada estándar


Salida

Las líneas, invertidas, a estándar.


Tanteo

Bytes de código fuente.

Nick T
fuente
99
taces un poco extraño cuando se trata de avances de línea finales. Se transforma a\nb\n(avance de línea final) en b\na\ny a\nb(sin avance de línea final) en ba\n. ¿Es así como se supone que debe comportarse nuestro código?
Dennis
Relacionado
Martin Ender
10
Además, si tenemos que replicar el comportamiento de tac, una respuesta Bash de 3 bytes que se ejecuta taces solo cuestión de tiempo ...
Dennis
1
@Dennis en este punto probablemente sea mejor dejarlo indefinido.
Nick T
1
@Dennis tiene sentido para mí. Visualice las líneas de un archivo como filas horizontales, todas terminando con \n. tacinvierte el orden de estas filas. Si \nse elimina una del medio del archivo, la fila que terminó se une a la siguiente fila, pero en el caso de la última línea, no hay una fila siguiente a la que unirse.
Blacklight Shining el

Respuestas:

15

GS2, 3 bytes

* +

Los tres bytes son, en orden, líneas divididas, líneas inversas y unidas.

recursivo
fuente
9

Perl, 11 bytes

$\=$_.$\}{

Se comporta exactamente igual tac. Este código requiere el -pinterruptor, que he contado como 1 byte.

Pruebas de funcionamiento

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

Cómo funciona

Como se explica aquí , el -pconmutador básicamente envuelve while (<>) { ... ; print }el programa, por lo que el código fuente es equivalente a

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

Para cada línea de entrada, anteponemos la línea actual ( $_) a $\(inicialmente indefinida), actualizando esta última con el resultado.

Después de que se hayan procesado todas las líneas, printimprime el valor de la variable local $_(indefinido en este ámbito), seguido del separador de registro de salida ( $\).

Dennis
fuente
¿Te importaría explicar cómo funciona esto?
xebtl
2
@xebtl Evilly. Agregar el -pinterruptor envuelve su código en un bucle que comienza while(<>){y termina } continue { print }, lo que permite filtrar la entrada simplemente modificando $_. $\=$_.$\antepone cada línea de entrada al terminador de registro de salida y }{finaliza el whilebloque suministrado por Perl prematuramente, por lo que el continuebloque ya no está conectado a él. Por lo tanto, todas las líneas de entrada se agregan $\en orden inverso, luego al final continue { print }se ejecuta, imprimiendo "nada" ( $_será indefinido después del final de la entrada), pero con un terminador de $\.
hobbs
@xebtl grr, el formato de código en los comentarios parece un poco roto cuando las barras invertidas y las barras invertidas se acercan entre sí. Quizás puedas adivinar lo que estaba tratando de decir.
hobbs
1
@primo El primer ejemplo muestra lo que sucede en este caso. La salida será extraña, pero exactamente igual a la de tac.
Dennis
1
@Dennis páginas 18 y siguientes de este libro
msh210
8

Pyth, 4 bytes

j_.z

.zes la entrada separada por líneas como una lista, la _invierte y june por un carácter, que por defecto es \n.

orlp
fuente
8

FlogScript , 2 bytes

)"

(Pruébelo en el golf de anarquía ).

El modo )habilita --in-out-line-array, y el resto del programa es ", invirtiendo la matriz de líneas.

Lynn
fuente
¡Argh, me ganaste!
mbomb007
7

Retina , 7 bytes

!rm`.*$

Con una sola expresión regular, Retina se ejecuta en modo Match. Esto normalmente solo imprime el número de coincidencias, pero con !esto lo configuramos para imprimir las coincidencias reales en su lugar (separadas por avances de línea).

La expresión regular real es meramente .*$. .*coincide con cualquier línea (potencialmente vacía), porque .puede coincidir con cualquier carácter, excepto los avances de línea. Llegaré al $en un minuto.

¿Cómo hacemos que imprima los partidos al revés? Al hacer uso del modo de coincidencia de derecha a izquierda de .NET, activado con r. Esto significa que el motor regex comienza al final de la cadena cuando busca coincidencias y funciona al revés.

Finalmente, mhace que la $coincidencia sea el final de una línea en lugar del final de la cadena. ¿Por qué necesitamos eso? El problema es que .*genera coincidencias extrañas. Considere la sustitución de expresiones regulares

s/a*/$0x/

aplicado a la entrada baaababaa. Pensarías que esto cedería baaaxbaxbaax, pero en realidad te da baaaxxbaxxbaaxx. ¿Por qué? Porque después de hacer coincidir aaael cursor del motor está entre el ay el b. Ahora ya no puede coincidir con as, pero a*también está satisfecho con una cadena vacía. Esto significa que, después de cada partido, obtienes otro partido vacío.

No queremos eso aquí, porque introduciría líneas vacías adicionales, por lo que descartamos esas coincidencias extrañas (que se encuentran al comienzo de las líneas, debido al modo de derecha a izquierda) al requerir que las coincidencias incluyan el final de la línea.

Martin Ender
fuente
6

Haskell, 34 bytes

main=interact$concat.reverse.lines

[editar]

Se guardó un byte reemplazándolo unlinescon concat.

jkabrg
fuente
4

CJam, 7 bytes

qN/W%N*

Lee stdin, imprime en stdout.

Explicación:

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

Befunge-93, 17 bytes

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

Nada lujoso aquí; simplemente pon todo en la pila, luego sácalo.

Kevin W.
fuente
4

Pure Bash (sin utilidades externas), 56

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

Esta es una de las pocas respuestas para hacer una tacemulación exacta , como se le preguntó en el comentario de 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.
$ 
Trauma digital
fuente
Agradable e inspirador .
manatwork
4

Ruby, 16 bytes

puts [*$<].reverse
daniero
fuente
4

JavaScript (SpiderMonkey Shell), 38 bytes

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

Bastante simple


read() lee un archivo

readline() lee una cadena de STDIN

[...str]dividirá str en una serie de caracteres

reverse() revertirá la matriz

join`` juntará la matriz en una cadena

Downgoat
fuente
4

Python 2, 52 bytes

import sys;print''.join(sys.stdin.readlines()[::-1])
Decaimiento Beta
fuente
1
¿Input () no lee una línea de stdin?
Lynn
@Mauris lo editó
Beta Decay
¿Qué hay de import sys;print sys.stdin.read()[::-1]?
Dieter
@dieter Que invierte a cada personaje, el desafío pide que solo se inviertan las líneas
Beta Decay
ok mi mal - No lo leí cuidadosamente, lo siento
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);}}

Lee líneas, colocándolas en una pila y luego las escribe al revés. Usaría Mathematica para esto, pero no tiene sentido de EOF.

LegionMammal978
fuente
3

sed, 9 bytes

1!G;h;$!d

No se necesita voto positivo, este es un famoso sed one-liner.

Steve
fuente
10
Si no es tu propio trabajo, te sugiero que hagas tu wiki de la comunidad de respuestas.
lirtosiast
3

Perl, 16 bytes

print reverse<>
Steve
fuente
@Dennis oops, ahora revertido.
Steve
3

Powershell, 41 bytes

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

Almacena el contenido de un archivo línea por línea a, lo invierte ay finalmente lo imprime.

patata dulce
fuente
3

GolfScript, 7 bytes

n/-1%n*

Prueba en línea aquí .

Cristian Lupascu
fuente
3

Burlesque , 6 bytes

ln<-uN

lndivide líneas, <-invierte, uNune líneas y formatos para salida sin formato.

Lynn
fuente
3

Bash, 48 43 caracteres

(Inspirado por Digital Trauma 's Bash respuesta . Upvotes de la idea debe ir a él.)

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

Ejecución de muestra:

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.
hombre trabajando
fuente
Creo que puedes hacer en mapfile -c1 -Cflugar de mapfile -c1 -Cf a.
Trauma digital
Correcto. Mientras tanto, también lo descubrí, solo intenté algo alrededor de ese truco -Cprimero.
manatwork
3

GNU Awk, 27 caracteres

(Inspirado por Ed Morton 's GNU Awk respuesta . CW que no tenía la intención de secuestrar a su solución.)

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

Tenga en cuenta que al cambiar RTRSesto se convierte en Awk estándar portátil pero pierde la capacidad de preservar la ausencia de la nueva línea final.

Ejecución de muestra:

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.
manatwork
fuente
Puede eliminar el "% s"
ninjalj
@ninjalj, solo si podemos suponer que la entrada nunca contendrá "%".
manatwork
3

SNOBOL, 42 bytes

S S =INPUT CHAR(10) S :S(S)
 OUTPUT =S
END
ninjalj
fuente
2

Gema, 25 personajes

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

Ejecución de muestra:

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
hombre trabajando
fuente
2

Hasio , 90 bytes 86 bytes

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

Ver expandido aquí

Jacob Misirian
fuente
1
Puedo acortar mucho esto abusando de la forsintaxis. Vea una muestra aquí
FryAmTheEggman
Buena llamada @FryAmTheEggman! Lo agregué.
Jacob Misirian
2

sed, 7 bytes

G;h;$!d

Esto funciona para mí (y es la solución más corta en otros lugares), pero realmente no quiero saber por qué. Acabo de perder el tiempo con el famoso truco de 9 bytes hasta que encontré esto. ¿Supongo que Gla primera línea no hace nada?

Lynn
fuente
2
Realmente hace algo: su código produce una nueva línea adicional al final de la salida. ( GAnexa un salto de línea y el contenido del espacio de bodega al espacio de patrones Si bien añadiendo el contenido del espacio de bodega vacío es de hecho inofensivo, el salto de línea todavía se anexa..)
manatwork
2

JavaScript (Node.js), 91 bytes

console.log(require('fs').readFileSync(process.argv[2])+"".split(d="\n").reverse().join(d))
Ben fortuna
fuente
¿Quiso decir console.log((require('fs').readFileSync(process.argv[2])+"").split(d="\n").reverse().join(d))(92 bytes)? Su código actual no invierte las líneas.
Cepillo de dientes
2

Bash + utilidades comunes, 25

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

Aquí el ^Ges un BELpersonaje literal . Supongo que la entrada es solo ascii imprimible.

Esto trresponde la entrada completa a una línea reemplazando las nuevas líneas con BEL, luego revborra esa línea, luego trregresa a revvarias líneas , luego borra cada línea nuevamente, para obtener la salida deseada.

Trauma digital
fuente
2

MATLAB, 44

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

Divide la cadena en nuevas líneas, voltea la matriz resultante y luego se une con nuevos caracteres de línea.

Tom Carpenter
fuente
2

Julia, 65 bytes

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

Esto toma un archivo como argumento de línea de comando e imprime sus líneas en orden inverso. Las nuevas líneas finales se mueven al frente, a diferencia de lo tacque es legítimo.

Sin golf:

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

Pip , 3 + 2 = 5 bytes

Utiliza las banderas ry n; lee de stdin.

RVg

La rbandera lee la entrada estándar y lo almacena como una lista de líneas en g(que normalmente es una lista de comando de la línea ar g s). Luego revertimos esa lista, y se imprime automáticamente. El nindicador hace que se generen listas con nueva línea como separador.

DLosc
fuente