Texte aligné à droite


27

Votre travail consiste à prendre une entrée de chaîne et un nombre et à aligner la chaîne à droite, en faisant de la largeur du texte le nombre. Quand une ligne est trop longue, cassez-la et mettez le reste sur la ligne suivante, en répétant jusqu'à ce que ce ne soit pas nécessaire. Si une ligne est plus courte que la largeur, remplissez-la avec des espaces. Plusieurs sauts de ligne peuvent se produire et doivent être traités comme tout autre caractère unique.

Par exemple, la chaîne

Programming
Puzzles
&
Code
Golf

et le nombre 5produirait:

Progr
ammin
    g
Puzzl
   es
    &
 Code
 Golf

Alors que la même chaîne et le même nombre 10produiraient:

Programmin
         g
   Puzzles
         &
      Code
      Golf

La chaîne

a

b

et le chiffre 5 produirait:

    a
      <-- note the 5 spaces
    b

Le code le plus court gagne!


1
Le texte dit «Brisez les lignes lorsque cela est nécessaire [...]», mais vos exemples suggèrent que vous coupez après chaque mot, même quand il conviendrait. Veuillez clarifier: plaçons-nous chaque mot sur une nouvelle ligne ou implémentons-nous un algorithme de retour à la ligne réel?
— Timwi

Peut-il y avoir des espaces au milieu d'une ligne d'entrée, par exemple Programming Puzzles\n&\nCode Golf?
— Sp3000

@ sp3000 Il peut y avoir n'importe quel caractère, y compris les espaces.
— Trebuchette

@Timwi: L'exemple a un mot par ligne. Il aurait été préférable d'inclure quelques lignes de plusieurs mots pour indiquer clairement que l'espace dans une ligne n'est pas spécial. (c'est-à-dire qu'il n'y a que des nouvelles lignes et des non-nouvelles lignes.)
— Peter Cordes

Réponses:



10

Python 2, 84

s,n=input()
for w in s.split('\n'):
 w=w or' '
 while w:print w[:n].rjust(n);w=w[n:]

Prend en entrée une chaîne avec des sauts de ligne et un nombre, et imprime le résultat. Pour chaque ligne de l'entrée, prend et imprime les ncaractères à la fois, en utilisant la fonction intégrée rjustpour remplir la gauche avec des espaces avant l'impression.

J'ai corrigé le cas de ligne vide avec le hack w=w or' '. Il y a probablement une meilleure méthode mais je ne vais pas y penser beaucoup.


8

CJam, 21 octets

li_qN/Sfe|f/ff{\Se[N}

Merci à @ Sp3000 pour avoir joué 1 octet et ouvert la voie à 3 autres.

Essayez-le en ligne dans l' interpréteur CJam .

Comment ça marche

li                     Read an integer L from the first line of input.
  _                    Push a copy.
   qN/                 Split the remaining input at linefeeds.
      Sfe|             Map `OR " "'; the replaces empty lines with a space.
          f/           Split each line into chunks of length L.
            ff{     }  For each chunk, push L and the chunk; then:
               \         Swap L with the chunk.
                Se[      Left-pad the chunk to length L by prepending " ".
                   N     Push a linefeed.

5

Pyth, 16

jm>Q+*\ QdscRQ.z

Essayez-le en ligne ici

Explication

jm>Q+*\ QdscRQ.z             : Q is the number on the first line, .z takes the rest
           cRQ.z             : chop each line of .z into chunks of Q characters
 m        s                  : remove nested lists and map over the result
    +*\ Qd                   : add Q spaces to each line d
  >Q                         : take the last Q characters of that result
j                            : join results on newlines

4

Perl, 39 octets

perl -ni5 -e 's!^$|.{1,$^I}!printf"%${^I}s
",$&!ge'

36 octets + 3 octets pour -ni. La largeur d'habillage est passée comme argument à -i.

Gère correctement les lignes vides en les remplissant d'espaces:

$ echo -e "Programming\nPuzzles\n\n&\n\nCode\nGolf" | perl -ni5 -e 's!^$|.{1,$^I}!printf"%${^I}s
",$&!ge'
Progr
ammin
    g
Puzzl
   es

    &

 Code
 Golf

Comment ça marche

Cette solution utilise l'opérateur de substitution pour parcourir l'entrée, économisant ainsi un octet sur la forboucle équivalente . Le vrai truc, cependant, est dans l'expression régulière sur le LHS de la substitution:

^$|.{1,$^I}

Avec le modificateur global, cela correspondra aux $^Icaractères à la fois; lorsqu'il reste moins de $^Icaractères dans la chaîne, tout correspondra jusqu'à la fin. L'alternance avec ^$est nécessaire pour gérer les lignes vierges. Par exemple:

$ echo -e "foo\n\nbar" | perl -ni2 -E 'say "<$_>" for /^$|.{1,$^I}/g'
<fo>
<o>
<>
<ba>
<r>

Le RHS de la substitution utilise simplement printfpour remplir à gauche le morceau correspondant avec des espaces.


J'oublie toujours $^I!
— Dom Hastings

@DomHastings J'ai appris cette astuce de chilemagic, qui l'a mentionné dans un commentaire sur un autre défi .
— ThisSuitIsBlackNot

3

Javascript (ES6), 107

Je souhaite que JS ait une fonction pad intégrée. Tant pis.

(a,b)=>a.replace(eval(`/(.{${b}})(?!\\n)/g`),`$1
`).split`
`.map(c=>(Array(b).join` `+c).slice(-b)).join`
`

Explication:

(a, b)=>

  // searches for sequences of characters longer than b without a newline after them and
  // adds a newline after every b characters of the sequence
  a.replace(eval(`/(.{${b}})(?!\\n)/g`), '$1\n')
    .split('\n')
    .map(c=>

      // prepends b spaces to each string then slices it from the right down to length b
      ( Array(b).join(' ') + c ).slice(-b)

    ).join('\n')

3

Julia, 126 octets

f(s,n)=for i=split(s,"\n") while length(i)>0 println(lpad(i[1:min(n,end)],n));length(i)<n?break:(i=i[min(n+1,end):end])end;end

Non golfé:

function f(s::String, n::Int)
    for i in split(s, "\n")
        while length(i) > 0
            println(lpad(i[1:min(n,end)], n))
            length(i) < n ? break : (i = i[min(n+1,end):end])
        end
    end
end

2

Bash, 62 , 61 + fonctionnalité, 59

Plus court s'il Npeut être défini par l'appelant, au lieu d'avoir à le lire comme première ligne d'entrée.

# width as a function arg: 59 chars
f()while read -rn$1 r;do [[ $r ]]&&printf %$1s\\n "$r";done
# width on stdin: 64 chars  (not updated with later suggestions&ideas)
read N;while read -rn$N r;do [[ $r ]]&&printf %$N's\n' "$r";done

Cela ne parvient pas à gérer les lignes vides dans l'entrée. Sinon, cela ne soumet pas les données d'entrée à la séparation des mots, à l'expansion du nom de chemin ou ne les traite pas comme plus que des données brutes.

read -n$Nenregistre un personnage, mais laisse readMunge \.

Le [[ $r ]]&&est nécessaire car read -n4ne peut pas regarder en avant pour voir que le prochain caractère est une nouvelle ligne. Il définit rdonc une chaîne de 4 caractères et la lecture suivante produit une chaîne vide de zéro caractère. Filtrer ces fausses nouvelles sans filtrer les vraies nouvelles lignes nécessiterait un état de suivi: que la ligne précédente ait ou non une longueur maximale. Il faudrait plus de code ou une approche totalement différente.

[[ $r ]]est plus court que [ -n "$r" ]ce qui est nécessaire pour éviter les erreurs si la ligne commence par -z foo, ou est *ou quelque chose, si vous l'avez utilisé [ $r ].

La justification se produit avec la chaîne de format standard printf "% 4s".

Testez avec

f()(while read -rn$1 r;do [[ $r ]]&&printf %$1s\\n "$r";done); (echo 4; echo -e "*\n\\"; cat /tmp/lines) | f 4

1. J'inclurais -rle nombre d'octets. 2. f()(while ... done)est un peu plus court.
— Dennis

@Dennis: Sans [[ $r ]]&&, si N = 4, une ligne d'entrée de longueur 4 produira une ligne de sortie vierge là où il n'y en avait pas auparavant. Parce que readrenvoie une chaîne de 4 caractères, puis voit une nouvelle ligne lors du prochain appel et revient immédiatement. Merci aussi pour l' ()astuce. Je ne savais pas que vous pouviez définir les fns de cette façon.
— Peter Cordes

Je recommande de lire des conseils pour jouer au golf à Bash . C'est une excellente ressource.
— Dennis

En fait, comme whilec'est déjà composé, vous n'avez même pas besoin des parenthèses:f()while ... done
— Dennis

@ Dennis: wow, haxx. Merci pour le lien. Quelques-unes de ces choses étaient nouvelles pour moi, et j'ai corrigé deux ou trois choses dans une autre réponse :) Je ne joue pas au golf normalement, mais> 15 ans d'expérience en tant que junkie en ligne de commande m'ont appris une chose ou deux :)
— Peter Cordes

2

Haskell, 108 octets

import Data.List.Split
k[]=[""]
k x=x
f n=unlines.(map(\l->([1..n-length l]>>" ")++l).k.chunksOf n=<<).lines

Exemple d'utilisation:

*Main> putStr $ f 5 "a\n\nb\ncd\nMatamorphosis"
    a

    b
   cd
Matam
orpho
  sis

Comment ça marche

                              .lines   -- split input string at newlines
                           =<<         -- for every line
                  chunksOf n           --    split into chunks of length n
                k                      --    fix empty lines
    map                                --    for every chunk
        \l->([1..n-length l]>>" "      --      make a string of missing spaces
                        ++l            --      and append the chunk
unlines                                -- join padded chunks with newlines in-between

1

GNU awk + bash, 70

f()(awk -vFPAT=.\{,$1} '{for(i=0;i++<NF;){printf "%'$1's\n",$i}}/^$/')

L'utilisation de bash pour insérer le compte dans le programme awk est problématique. plus petit que le lire avec un NR==1{N=$0}bloc.

Lisez une ligne à la fois. Divisez-vous en 4 caractères au maximum, en utilisant FPAT. (correspond aux champs, plutôt qu'aux séparateurs. Extension GNU.) printf chaque champ séparément. (ORS par défaut = \ n).

La /^$/règle est là pour imprimer des lignes vides, qui ont NF = 0 et donc ne s'impriment pas du tout dans l'autre bloc. Contrairement à ma solution pure-bash, cela fonctionne en fait dans le cas général.

Semi-indépendant, mais mon idée jusqu'à présent pour Perl est de 112 caractères pour juste le code Perl:

(echo 4; echo -e 'foo\nbar'; echo -e "*\n\\"; echo '~$(true)'; cat /tmp/lines) |  # test input
perl -e '$N=<>;$/=\1;print "$N\n"; while(<>){if(/\n/ or length($l)>=$N){printf("%$4s\n",$l);$l=/\n/?"":$_;}else{$l.=$_;}}'

Cela mange l'une des nouvelles lignes et est beaucoup trop long. $/=\1lit un octet à la fois. Nous ajoutons à $ l. Une approche ligne par ligne avec une approche de largeur fixe serait probablement plus courte.


1

Utilitaires Bash + GNU, 41

fold -$1|sed ":;s/^.\{,$[$1-1]\}\$/ &/;t"

La chaîne est entrée via STDIN, la largeur est entrée par la ligne de commande arg:

ubuntu@ubuntu:~$ echo 'Programming
Puzzles
&
Code
Golf'|./ralign.sh 10
Programmin
         g
   Puzzles
         &
      Code
      Golf
ubuntu@ubuntu:~$

1

Python 2, 151 octets

s,n=input();N='\n'
for w in[i.lstrip()if i.replace(' ','').isalpha()else i for i in s.replace(N,'\n ').split(N)]:
 while w:print w[:n].rjust(n);w=w[n:]

Il s'agit d'une adaptation de la réponse de @ xnor ci-dessus, car la sienne ne gère pas correctement les nouvelles lignes.


La forboucle a été modifiée de:

for w in s.split('\n'):

à:

for w in[i.lstrip()if i.replace(' ','').isalpha()else i for i in s.replace(N,'\n ').split(N)]:

Exemple

$ python main.py
"Programming\n\n\nPuzzles\n\n&\n\nCode\nGolf", 5
Progr
ammin
    g


Puzzl
   es

    &

 Code
 Golf

1

C #, 143 octets

(s,n)=>Join("\n",s.Split('\n').SelectMany(l=>(l.Any()?l:" ").Select((c,i)=>new{c,i}).GroupBy(o=>o.i/n,o=>o.c).Select(g=>Concat(g).PadLeft(n))))

Linq vous permet de faire des expressions assez noueuses. GroupByest utile ici, mais c'est dommage qu'ils n'aient pas pu créer de surcharge de fonction en prenant l'index.

Attribuer le lambda à un Func<string, int, string>pour l'exécuter

Moins golfé:

Func<string, int, string> Align = (s, n) => Join("\n", 
    s.Split('\n')
     .SelectMany(l => (l.Any() ? l : " ")
         .Select((c, i) => new { c, i })
         .GroupBy(o => o.i / n, o => o.c)
         .Select(g => Concat(g).PadLeft(n))));

1

Groovy, 63 octets

Renvoie la chaîne correctement allouée. Je ne savais pas qu'il y avait jusqu'à présent une fonction padLeft (et padRight, padCenter).

f={s,n->s.split("(?<=\\G.{$n})|\n")*.padLeft(n," ").join("\n")}

1

Javascript 174 136

function R(s,x){return s.replace(new RegExp(".{"+x+"}","g"),"$&\n").replace(/[^\n]*/g,function(m){
while(m.length<x)m=" "+m;return m;})}

1

Ceylan, 107

String w(String s,Integer n)=>"\n".join{for(l in s.lines)for(p in l.partition(n))String(p).padLeading(n)};

1

Matlab, 99 octets

Merci à @beaker pour avoir supprimé 6 octets!

Utilisation et fonction anonyme:

@(s,k)fliplr(char(cellfun(@fliplr,strsplit(regexprep(s,sprintf('\\S{%i}',k),'$0\n'),'\n'),'un',0))) 

Définissez la fonction et utilisez-la anspour l'appeler:

>> @(s,k)fliplr(char(cellfun(@fliplr,strsplit(regexprep(s,sprintf('\\S{%i}',k),'$0\n'),'\n'),'un',0)))

ans =

@(s,k)fliplr(char(cellfun(@fliplr,strsplit(regexprep(s,sprintf('\\S{%i}',k),'$0\n'),'\n'),'un',0)))

>> ans(['Programming' 10 'Puzzles' 10 '&' 10 'Code' 10 'Golf'], 5) %% 10 is line feed

ans =

Progr
ammin
    g
Puzzl
   es
    &
 Code
 Golf

1

Burlesque, 28 octets

Identique à la version ci-dessous, mais traite la ligne 1 comme le nombre et les autres lignes comme la chaîne.

lng_riPpun{pPco{pP' lp}mu}Wl

Utilisation comme dans:

$ cat input.txt | blsq --stdin "lng_riPpun{pPco{pP' lp}mu}Wl"
Progr
ammin
    g
Puzzl
   es
    &
 Code
 Golf

Ancienne version (16 octets):

{5co{5' lp}mu}Wl

Exemple:

blsq ) "Programming\nPuzzles\n&\nCode\nGolf"{5co{5' lp}mu}Wl
Progr
ammin
    g
Puzzl
   es
    &
 Code
 Golf
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.