Implemente “tac”: imprima linhas de um arquivo em sentido inverso


30

Entre a pergunta do gatinho e ver essa pergunta na U&L sobre alguma sedmágica, que tal implementar tac?


Objetivo

Implemente um programa que reverterá e imprimirá as linhas em um arquivo.


Entrada

Um arquivo, fornecido como um nome ou via entrada padrão


Saída

As linhas, invertidas, são padronizadas.


Pontuação

Bytes do código fonte.


9
tacé um pouco estranho quando se trata de rastrear feeds de linha. Ele transforma a\nb\n(avanço de linha à direita) em b\na\ne a\nb(sem avanço de linha à direita) em ba\n. É assim que nosso código deveria se comportar?
Dennis


10
Além disso, se temos que o comportamento do tac réplica, a 3 bytes Bash respostas que executa tacé apenas uma questão de tempo ...
Dennis

1
@Dennis neste momento provavelmente é melhor deixar indefinido.
Nick T

1
@Dennis Faz sentido para mim. Visualize as linhas de um arquivo como linhas horizontais, todas terminadas em \n. tacinverte a ordem dessas linhas. Se um \nfor removido do meio do arquivo, a linha finalizada será associada à próxima linha, mas, no caso da última linha, não haverá próxima linha para a qual ingressar.
Blacklight Shining

Respostas:


15

GS2, 3 bytes

* +

Os três bytes são, em ordem, dividir linhas, reverter e unir linhas.


9

Perl, 11 bytes

$\=$_.$\}{

Comporta-se exatamente como tac. Esse código requer a -popção, que contei como 1 byte.

Execuções de teste

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

Como funciona

Como explicado aqui , o -pswitch basicamente envolve while (<>) { ... ; print }o programa, portanto o código fonte é equivalente a

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

Para cada linha de entrada, acrescentamos a linha atual ( $_) a $\(inicialmente indefinida), atualizando a última com o resultado.

Após o processamento de todas as linhas, printimprime o valor da variável local $_(indefinida neste escopo), seguida pelo separador do registro de saída ( $\).


Gostaria de explicar como isso funciona?
Xebtl

2
@xebtl Evilly. A adição do -pcomutador envolve seu código em um loop que começa while(<>){e termina } continue { print }, o que permite filtrar a entrada apenas modificando $_. $\=$_.$\precede cada linha de entrada ao terminador do registro de saída e }{finaliza o whilebloco fornecido perl prematuramente, para que o continuebloco não esteja mais anexado a ele. Portanto, todas as linhas de entrada são adicionadas $\na ordem inversa; no final, continue { print }eventualmente, é executado, imprimindo "nada" ( $_será indefinido após o final da entrada), mas com um terminador de $\.
Hbbs #

@xebtl grr, a formatação de código nos comentários parece um pouco quebrada, quando barras invertidas e barras de reticulação se aproximam. Talvez você possa adivinhar o que eu estava tentando dizer.
Hbbs #

1
@primo O primeiro exemplo mostra o que acontece neste caso. A saída será estranha, mas exatamente como a TAC.
Dennis

1
@Dennis páginas 18 e seguintes deste livro
msh210

8

Pitão, 4 bytes

j_.z

.zé a entrada separada por linhas como uma lista, a _reverte e june-a por um caractere, que por padrão é \n.



7

Retina , 7 bytes

!rm`.*$

Com um único regex, o Retina é executado no modo de correspondência. Normalmente, isso apenas imprime o número de correspondências, mas, com !isso, configuramos para imprimir as correspondências reais (separadas por linhas de alimentação).

O regex real é apenas .*$. .*corresponde a qualquer linha (potencialmente vazia), porque .pode corresponder a qualquer caractere, exceto feeds de linha. Eu vou chegar $em um minuto.

Como podemos imprimir as correspondências ao contrário? Utilizando o modo de correspondência da direita para a esquerda do .NET, ativado com o r. Isso significa que o mecanismo regex inicia no final da string ao procurar correspondências e funciona ao contrário.

Finalmente, mfaz com que a $correspondência seja o final de uma linha, em vez do final da sequência. Por que precisamos disso? O problema é que .*gera correspondências estranhas. Considere a substituição de regex

s/a*/$0x/

aplicado à entrada baaababaa. Você pensaria que isso renderia baaaxbaxbaax, mas realmente lhe dá baaaxxbaxxbaaxx. Por quê? Porque, depois de corresponder, aaao cursor do mecanismo fica entre o ae o b. Agora não pode mais corresponder as, mas a*também está satisfeito com uma sequência vazia. Isso significa que, após cada partida, você recebe outra partida vazia.

Não queremos isso aqui, porque isso introduziria linhas vazias adicionais; portanto, descartamos essas correspondências estranhas (que estão no início das linhas, devido ao modo da direita para a esquerda), exigindo que as correspondências incluam o final de a linha.


6

Haskell, 34 bytes

main=interact$concat.reverse.lines

[editar]

Salvo um byte, substituindo unlinespor concat.


4

CJam, 7 bytes

qN/W%N*

Lê stdin, imprime em stdout.

Explicação:

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


4

Befunge-93, 17 bytes

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

Nada extravagante aqui; basta colocar tudo na pilha e soltar.


4

Pure Bash (sem utilitários externos), 56

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

Esta é uma das poucas respostas para fazer a tacemulação exata , conforme perguntado no comentário 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.
$ 

Agradável e inspirador .
manatwork


4

JavaScript (SpiderMonkey Shell), 38 bytes

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

Bem simples


read() lê um arquivo

readline() lê uma string de STDIN

[...str]irá dividir str em uma matriz de caracteres

reverse() irá reverter a matriz

join`` irá recolher a matriz em uma string


4

Python 2, 52 bytes

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

1
O input () não lê uma linha do stdin?
Lynn

@Mauris Editou
Decaimento Beta

Que tal import sys;print sys.stdin.read()[::-1]?
Dieter

@dieter que inverte cada personagem, o desafio pede apenas as linhas para ser revertidas
Beta Decay

ok meu mau - Não lê-lo com cuidado, desculpe
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);}}

Lê linhas, colocando-as em uma pilha e depois as grava para trás. Eu usaria o Mathematica para isso, mas ele não tem senso de EOF.


3

sed, 9 bytes

1!G;h;$!d

Nenhum voto positivo desejado, este é um famoso sed one-liner.


10
Se não for seu próprio trabalho, sugiro que você responda ao wiki da comunidade.
Lirtosiast


3

Powershell, 41 bytes

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

Armazena o conteúdo de um arquivo linha por linha a, inverte ae finalmente o imprime.



3

Burlesco , 6 bytes

ln<-uN

lndivide linhas, <-inverte, uNune linhas e formatos para saída bruta.


3

Bash, 48 43 caracteres

(Inspirado por Trauma Digital 's resposta Bash . Upvotes para a idéia deve ir até ele.)

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

Exemplo de execução:

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.

Eu acho que você pode fazer em mapfile -c1 -Cfvez de mapfile -c1 -Cf a.
Digital Trauma

Corrigir. Eu também descobri isso enquanto isso, tentei algo em torno dessa coisa complicada -Cprimeiro.
Manatwork

3

GNU Awk, 27 caracteres

(Inspirado Ed Morton de resposta GNU Awk . CW como eu não se destinam a sequestrar a sua solução.)

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

Observe que, ao alterar RT→, RSele se torna o Awk padrão portátil, mas perde a capacidade de preservar a ausência da nova linha final.

Exemplo de execução:

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.

Você pode remover o "% s"
ninjalj

@ninjalj, apenas se pudermos assumir que a entrada nunca conterá "%".
manatwork

3

SNOBOL, 42 bytes

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

2

Gema, 25 caracteres

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

Exemplo de execução:

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

Isso funciona para mim (e é a solução mais curta em outro lugar), mas eu realmente não quero descobrir o porquê. Eu apenas brinquei com o famoso truque de 9 bytes até encontrar isso. Eu acho que Ga primeira linha não faz nada?


2
Realmente faz algo: seu código produz uma nova linha extra no final da saída. ( GAcrescenta uma nova linha e o conteúdo do espaço de sustentação para o espaço padrão acrescentando Enquanto o conteúdo do espaço vazio é de facto preensão inofensivo, a nova linha ainda é anexado..)
manatwork

2

JavaScript (Node.js), 91 bytes

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

Você quis dizer console.log((require('fs').readFileSync(process.argv[2])+"").split(d="\n").reverse().join(d))(92 bytes)? Seu código atual não reverte as linhas.
Escova de dentes

2

Bash + utilitários comuns, 25

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

Aqui o ^Gé um BELcaractere literal . Estou assumindo que a entrada é apenas ascii imprimível.

Isso trtransforma toda a entrada em uma linha, substituindo novas linhas por BELs, em seguida, revaltera essa linha e, em seguida, trretorna para revvárias linhas , depois altera cada linha novamente, para obter a saída desejada.


2

MATLAB, 44

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

Divide a sequência em novas linhas, vira a matriz resultante e volta a juntar-se a novos caracteres de linha.


2

Julia, 65 bytes

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

Isso pega um arquivo como argumento de linha de comando e imprime suas linhas na ordem inversa. As novas linhas à direita são movidas para a frente, ao contrário do tacque é legítimo.

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

Usa as bandeiras re n; lê de stdin.

RVg

A rbandeira lê stdin e armazena-o como uma lista de linhas em g(que é normalmente uma lista de-ar da linha de comando g s). Em seguida, invertemos essa lista e ela é impressa automaticamente. O nsinalizador faz com que as listas sejam produzidas com nova linha como separador.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.