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.


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


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.


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 ( $\).


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



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.


6

Haskell, 34 bytes

main=interact$concat.reverse.lines

[editar]

Se guardó un byte reemplazándolo unlinescon concat.


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.


4

Befunge-93, 17 bytes

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

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


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

Agradable e inspirador .
manatwork


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


4

Python 2, 52 bytes

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

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.


3

sed, 9 bytes

1!G;h;$!d

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


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


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.



3

Burlesque , 6 bytes

ln<-uN

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


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.

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.

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

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


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?


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

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


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.


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

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.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.