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.