Implémenter «tac»: imprimer les lignes d'un fichier en sens inverse

30

Entre la question du chaton et voir cette question à U&L sur la sedmagie, que diriez-vous de l'implémentation tac?


Objectif

Implémentez un programme qui inversera et imprimera les lignes dans un fichier.


Contribution

Un fichier, fourni sous forme de nom ou via une entrée standard


Sortie

Les lignes, inversées, à la sortie standard.


Notation

Octets de code source.

Nick T
la source
9
tacest un peu étrange en ce qui concerne les sauts de ligne de fin. Il transforme a\nb\n(saut de ligne arrière) en b\na\net a\nb(pas de saut de ligne arrière) en ba\n. Est-ce ainsi que notre code devrait se comporter?
Dennis
Connexes
Martin Ender
10
De plus, si nous devons reproduire le comportement de tac, une réponse Bash de 3 octets qui s'exécute tacn'est qu'une question de temps ...
Dennis
1
@Dennis à ce stade est probablement préférable de laisser indéfini.
Nick T
1
@Dennis est logique pour moi. Visualisez les lignes d'un fichier sous forme de lignes horizontales, toutes se terminant par \n. tacinverse l'ordre de ces lignes. Si an \nest supprimé du milieu du fichier, la ligne qu'il a terminée est jointe à la ligne suivante, mais dans le cas de la dernière ligne, il n'y a pas de ligne suivante à joindre.
Blacklight Shining du

Réponses:

15

GS2, 3 octets

* +

Les trois octets sont, dans l'ordre, les lignes divisées, inversées et jointes.

récursif
la source
9

Perl, 11 octets

$\=$_.$\}{

Se comporte exactement comme tac. Ce code nécessite le -pcommutateur, que j'ai compté comme 1 octet.

Essais

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

Comment ça marche

Comme expliqué ici , le -pcommutateur while (<>) { ... ; print }entoure essentiellement le programme, donc le code source est équivalent à

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

Pour chaque ligne d'entrée, nous ajoutons la ligne actuelle ( $_) à $\(initialement non définie), en mettant à jour cette dernière avec le résultat.

Une fois toutes les lignes traitées, printimprime la valeur de la variable locale $_(non définie dans cette étendue), suivie du séparateur d'enregistrement de sortie ( $\).

Dennis
la source
Vous voulez expliquer comment cela fonctionne?
xebtl
2
@xebtl Evilly. L'ajout du -pcommutateur enveloppe votre code dans une boucle qui commence while(<>){et se termine } continue { print }, ce qui permet de filtrer les entrées simplement en les modifiant $_. $\=$_.$\ajoute chaque ligne d'entrée au terminateur d'enregistrement de sortie et }{termine le whilebloc fourni par Perl prématurément, de sorte que le continuebloc n'y est plus attaché. Donc, toutes les lignes d'entrée sont ajoutées $\dans l'ordre inverse, puis à la fin continue { print }, elles s'exécutent finalement, en imprimant "rien" ( $_sera indéfini après la fin de l'entrée), mais avec un terminateur de $\.
Hobbs
@xebtl grr, le formatage du code dans les commentaires semble un peu cassé là où les antislashs et les backticks se rapprochent. Vous pouvez peut-être deviner ce que j'essayais de dire.
hobbs
1
@primo Le premier exemple montre ce qui se passe dans ce cas. La sortie sera étrange, mais exactement comme celle de tac.
Dennis
1
@Dennis pages 18 ff de ce livre
msh210
8

Pyth, 4 octets

j_.z

.zest l'entrée séparée par des lignes sous forme de liste, l' _inverse et la jjoint par un caractère, qui par défaut est \n.

orlp
la source
8

FlogScript , 2 octets

)"

(Essayez-le sur le golf d'anarchie .)

Le mode )enable --in-out-line-array, et le reste du programme est ", inversant le tableau de lignes.

Lynn
la source
Argh, tu m'as battu!
mbomb007
7

Rétine , 7 octets

!rm`.*$

Avec une seule expression régulière, Retina s'exécute en mode Match. Cela n'imprime normalement que le nombre de correspondances, mais avec !nous le configurons pour imprimer les correspondances réelles à la place (séparées par des sauts de ligne).

Le regex réel est simplement .*$. .*correspond à n'importe quelle ligne (potentiellement vide), car .peut correspondre à n'importe quel caractère à l'exception des sauts de ligne. J'y arriverai $dans une minute.

Comment faire imprimer les allumettes à l'envers? En utilisant le mode de correspondance de droite à gauche de .NET, activé avec le r. Cela signifie que le moteur d'expression régulière démarre à la fin de la chaîne lors de la recherche de correspondances et fonctionne à l'envers.

Enfin, le mfait $correspondre la fin d'une ligne au lieu de la fin de la chaîne. Pourquoi en avons-nous même besoin? Le problème est que cela .*génère des correspondances étrangères. Considérez la substitution d'expression régulière

s/a*/$0x/

appliqué à l'entrée baaababaa. Vous penseriez que cela donnerait baaaxbaxbaax, mais cela vous donne en fait baaaxxbaxxbaaxx. Pourquoi? Parce qu'après avoir fait correspondre aaale curseur du moteur se trouve entre le aet le b. Maintenant, il ne peut plus correspondre à as, mais il a*est également satisfait d'une chaîne vide. Cela signifie qu'après chaque match, vous obtenez un autre match vide.

Nous ne voulons pas cela ici, car cela introduirait des lignes vides supplémentaires, donc nous supprimons ces correspondances étrangères (qui sont au début des lignes, en raison du mode de droite à gauche) en exigeant que les correspondances incluent la fin la ligne.

Martin Ender
la source
6

Haskell, 34 octets

main=interact$concat.reverse.lines

[modifier]

Un octet enregistré en remplaçant unlinespar concat.

jkabrg
la source
4

CJam, 7 octets

qN/W%N*

Lit stdin, imprime sur stdout.

Explication:

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

Befunge-93, 17 octets

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

Rien d'extraordinaire ici; il suffit de tout mettre sur la pile, puis de le retirer.

Kevin W.
la source
4

Pure Bash (pas d'utilitaires externes), 56

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

C'est l'une des rares réponses à faire une tacémulation exacte , comme demandé dans le commentaire 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.
$ 
Traumatisme numérique
la source
Agréable et inspirant .
manatwork
4

Ruby, 16 octets

puts [*$<].reverse
daniero
la source
4

JavaScript (SpiderMonkey Shell), 38 octets

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

Assez simple


read() lit un fichier

readline() lit une chaîne de STDIN

[...str]divisera str en un tableau de caractères

reverse() inversera le tableau

join`` collpase le tableau dans une chaîne

Downgoat
la source
4

Python 2, 52 octets

import sys;print''.join(sys.stdin.readlines()[::-1])
Beta Decay
la source
1
Input () ne lit-il pas une ligne de stdin?
Lynn du
@Mauris Edited it
Beta Decay
Et alors import sys;print sys.stdin.read()[::-1]?
dieter
@dieter Cela inverse chaque personnage, le défi demande juste que les lignes soient inversées
Beta Decay
ok mon mauvais - Je ne l'ai pas lu attentivement, désolé
dieter
4

C #, 179 171 octets

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

Lit les lignes, les place dans une pile, puis les écrit à l'envers. J'utiliserais Mathematica pour cela, mais cela n'a aucun sens d'EOF.

LegionMammal978
la source
3

sed, 9 octets

1!G;h;$!d

Pas de vote positif, c'est un fameux monoplace sed.

Steve
la source
10
Si ce n'est pas votre propre travail, je vous suggère de faire votre wiki communautaire de réponse.
lirtosiast
3

Perl, 16 octets

print reverse<>
Steve
la source
@ Dennis oops, maintenant rétabli.
steve
3

Powershell, 41 octets

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

Stocke le contenu d'un fichier ligne par ligne a, l'inverse aet l'imprime finalement.

patate douce
la source
3

GolfScript, 7 octets

n/-1%n*

Test en ligne ici .

Cristian Lupascu
la source
3

Burlesque , 6 octets

ln<-uN

lndivise les lignes, <-inverse, uNjoint les lignes et les formats pour la sortie brute.

Lynn
la source
3

Bash, 48 43 caractères

(Inspirés par le numérique Trauma de réponse Bash . Upvotes l'idée devrait aller à lui.)

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

Exemple d'exécution:

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.
homme au travail
la source
Je pense que vous pouvez faire à la mapfile -c1 -Cfplace de mapfile -c1 -Cf a.
Digital Trauma
Correct. Je l'ai également découvert en attendant, j'ai juste essayé quelque chose autour de ce délicat en -Cpremier.
manatwork
3

GNU Awk, 27 caractères

(Inspiré par Ed Morton de réponse GNU Awk . CW que je ne comptais pirater sa solution.)

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

Notez qu'en changeant RTRScela devient Awk standard portable mais perd la possibilité de préserver l'absence de la nouvelle ligne finale.

Exemple d'exécution:

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.
2 tours
la source
Vous pouvez supprimer le "% s"
ninjalj
@ninjalj, seulement si l'on peut supposer que l'entrée ne contiendra jamais «%».
manatwork
3

SNOBOL, 42 octets

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

Gema, 25 caractères

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

Exemple d'exécution:

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
homme au travail
la source
2

Hassium , 90 octets 86 octets

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

Voir développé ici

Jacob Misirian
la source
1
Je vous raccourcis beaucoup en abusant de la forsyntaxe. Voir un exemple ici
FryAmTheEggman
Bon appel @FryAmTheEggman! Je l'ai ajouté.
Jacob Misirian
2

sed, 7 octets

G;h;$!d

Cela fonctionne pour moi (et c'est la solution la plus courte ailleurs), mais je ne veux pas vraiment savoir pourquoi. Je viens de jouer avec le fameux truc de 9 octets jusqu'à ce que je trouve cela. Je suppose Gque la première ligne ne fait rien?

Lynn
la source
2
Fait en fait quelque chose: votre code produit une nouvelle ligne supplémentaire à la fin de la sortie. ( Gajoute une nouvelle ligne et le contenu de l'espace de rétention à l'espace de motif. Bien que l'ajout du contenu de l'espace de
rétention
2

JavaScript (Node.js), 91 octets

console.log(require('fs').readFileSync(process.argv[2])+"".split(d="\n").reverse().join(d))
Ben Fortune
la source
Voulez-vous dire console.log((require('fs').readFileSync(process.argv[2])+"").split(d="\n").reverse().join(d))(92 octets)? Votre code actuel n'inverse pas les lignes.
Brosse à dents du
2

Bash + utilitaires communs, 25

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

Ici, ^Gc'est un BELcaractère littéral . Je suppose que l'entrée est uniquement ascii imprimable.

Cela permet de trformer l'intégralité de l'entrée sur une ligne en remplaçant les sauts de ligne par des BEL, puis de revsupprimer cette ligne, puis de trretourner en multiligne, puis de revreplacer chaque ligne à nouveau, pour obtenir la sortie souhaitée.

Traumatisme numérique
la source
2

MATLAB, 44

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

Fractionne la chaîne à de nouvelles lignes, retourne le tableau résultant, puis rejoint avec de nouveaux caractères de ligne.

Tom Carpenter
la source
2

Julia, 65 octets

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

Cela prend un fichier comme argument de ligne de commande et imprime ses lignes dans l'ordre inverse. Les nouvelles lignes de fin sont déplacées vers l'avant, contrairement à tacce qui est légitime.

Non 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.
la source
2

Pip , 3 + 2 = 5 octets

Utilise les drapeaux ret n; lit de stdin.

RVg

Le rdrapeau indique l' entrée standard et le stocke en tant que liste de lignes g(qui est normalement une liste de ligne de commande ar g s). Nous inversons ensuite cette liste et elle est imprimée automatiquement. L' nindicateur provoque la sortie des listes avec la nouvelle ligne comme séparateur.

DLosc
la source