Texto de alineación a la derecha

27

Su trabajo es tomar una entrada de cadena y un número y alinear la cadena a la derecha, haciendo que el ancho del texto sea el número. Cuando una línea es demasiado larga, sepárela y coloque el resto en la siguiente línea, repitiendo hasta que no sea necesario. Si una línea es más corta que el ancho, rellene con espacios. Pueden aparecer varias líneas nuevas y deben tratarse como cualquier otro carácter individual.

Por ejemplo, la cadena

Programming
Puzzles
&
Code
Golf

y el número 5produciría:

Progr
ammin
    g
Puzzl
   es
    &
 Code
 Golf

Mientras que la misma cadena y el número 10producirían:

Programmin
         g
   Puzzles
         &
      Code
      Golf

La cuerda

a

b

y el número 5 produciría:

    a
      <-- note the 5 spaces
    b

¡El código más corto gana!

Trebuchette
fuente
1
El texto dice "Rompe las líneas cuando sea necesario [...]", pero tus ejemplos sugieren que rompes después de cada palabra, incluso cuando encaja. Por favor aclare: ¿colocamos cada palabra en una nueva línea o implementamos un algoritmo de ajuste de palabras real?
Timwi
¿Puede haber espacios en el medio de una línea de entrada, por ejemplo Programming Puzzles\n&\nCode Golf?
Sp3000
@ sp3000 Puede haber cualquier carácter, incluidos los espacios.
Trebuchette
@Timwi: el ejemplo tiene una palabra por línea. Hubiera sido mejor incluir algunas líneas de varias palabras para dejar en claro que el espacio dentro de una línea no es especial. (es decir, solo hay líneas nuevas y no nuevas).
Peter Cordes

Respuestas:

8

Pyth, 14 bytes

jm.[\ QdscRQ.z

Demostración

Utiliza el operador de almohadilla de Pyth.

isaacg
fuente
10

Pitón 2, 84

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

Toma como entrada una cadena con nuevas líneas y un número, e imprime el resultado. Para cada línea en la entrada, toma e imprime ncaracteres a la vez, usando el incorporado rjustpara rellenar la izquierda con espacios antes de imprimir.

Arreglé el caso de la línea vacía con el truco w=w or' '. Probablemente haya un método mejor, pero no voy a pensar mucho en ello.

xnor
fuente
8

CJam, 21 bytes

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

Gracias a @ Sp3000 por jugar 1 byte y allanar el camino para 3 más.

Pruébelo en línea en el intérprete de CJam .

Cómo funciona

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.
Dennis
fuente
5

Pyth, 16

jm>Q+*\ QdscRQ.z

Pruébalo en línea aquí

Explicación

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
FryAmTheEggman
fuente
4

Perl, 39 bytes

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

36 bytes + 3 bytes para -ni. El ancho de ajuste se pasa como argumento a -i.

Maneja las líneas en blanco correctamente rellenándolas con espacios:

$ 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

Cómo funciona

Esta solución utiliza el operador de sustitución para recorrer la entrada, guardando un byte sobre el forciclo equivalente . Sin embargo, el verdadero truco está en la expresión regular en el LHS de la sustitución:

^$|.{1,$^I}

Con el modificador global, esto coincidirá con los $^Icaracteres a la vez; cuando quedan menos de $^Icaracteres en la cadena, coincidirá todo hasta el final. La alternancia con ^$se requiere para manejar líneas en blanco. Por ejemplo:

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

El RHS de la sustitución simplemente se usa printfpara rellenar a la izquierda el fragmento coincidente con espacios.

ThisSuitIsBlackNot
fuente
¡Siempre me olvido $^I!
Dom Hastings
@DomHastings Aprendí ese truco de chilemagic, quien lo mencionó en un comentario sobre otro desafío .
ThisSuitIsBlackNot
3

Javascript (ES6), 107

Desearía que JS tuviera una función de almohadilla integrada. Oh bien.

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

Explicación:

(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')
DankMemes
fuente
3

Julia, 126 bytes

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

Sin 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
Alex A.
fuente
2

Bash, 62 , 61 + función, 59

Más corto si Npuede establecerlo la persona que llama, en lugar de tener que leerlo como la primera línea de entrada.

# 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

Esto no puede manejar líneas vacías en la entrada. De lo contrario, esto no somete los datos de entrada a la división de palabras, la expansión del nombre de ruta ni los trata como algo más que solo datos sin procesar.

read -n$Nsalva a un personaje, pero vamos a readmachacar \.

Se [[ $r ]]&&necesita porque read -n4no puede mirar hacia adelante para ver que el próximo carácter es una nueva línea. Por lo tanto, se establece ren una cadena de 4 caracteres, y la siguiente lectura produce una cadena vacía de cero caracteres. Filtrar estas nuevas líneas falsas sin filtrar nuevas líneas reales requeriría un estado de seguimiento: si la línea anterior era de longitud máxima o no. Se necesitaría más código o un enfoque totalmente diferente.

[[ $r ]]es más corto de [ -n "$r" ]lo necesario para evitar errores si la línea comienza con -z foo, o es *o algo, si lo usó [ $r ].

La justificación ocurre con la cadena de formato estándar printf "% 4s".

Prueba con

f()(while read -rn$1 r;do [[ $r ]]&&printf %$1s\\n "$r";done); (echo 4; echo -e "*\n\\"; cat /tmp/lines) | f 4
Peter Cordes
fuente
1. Yo incluiría -ren el conteo de bytes. 2. f()(while ... done)es un poco más corto.
Dennis
@Dennis: sin [[ $r ]]&&N, si 4 =, una línea de entrada de longitud 4 producirá una línea de salida en blanco donde no había una antes. Debido a que readdevuelve una cadena de 4 caracteres, luego ve una nueva línea en la próxima llamada y regresa de inmediato. Además, gracias por el ()consejo. No sabía que pudieras definir los fns de esa manera.
Peter Cordes
Recomiendo leer Consejos para jugar al golf en Bash . Es un gran recurso.
Dennis
En realidad, dado whileque ya está compuesto, ni siquiera necesita los paréntesis:f()while ... done
Dennis
@ Dennis: wow, haxx. Gracias por el enlace. Un par de esas cosas eran nuevas para mí, y arreglé un par de cosas en otra respuesta :) No suelo jugar al golf, pero> 15 años de ser un adicto a la línea de comandos me ha enseñado una o dos cosas :)
Peter Cordes
2

Haskell, 108 bytes

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

Ejemplo de uso:

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

    b
   cd
Matam
orpho
  sis

Cómo funciona

                              .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
nimi
fuente
1

GNU awk + bash, 70

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

Usar bash para colocar el conteo en el programa awk es un problema. más pequeño que leerlo con un NR==1{N=$0}bloque.

Lee una línea a la vez. Dividir en un máximo de 4 fragmentos de caracteres, usando FPAT. (coincide con los campos, en lugar de los separadores. Extensión GNU). printf cada campo por separado. (ORS predeterminado = \ n).

La /^$/regla está ahí para imprimir líneas vacías, que tienen NF = 0 y, por lo tanto, no imprimen en absoluto en el otro bloque. Entonces, a diferencia de mi solución pure-bash, esto realmente funciona en el caso general.

Semi-sin relación, pero mi idea hasta ahora para perl es 112 caracteres para solo el código 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.=$_;}}'

Esto se come una de las nuevas líneas y es demasiado largo. $/=\1lee un byte a la vez. Anexamos $ l. Probablemente una línea a la vez con enfoque dividido de ancho fijo sería más corta.

Peter Cordes
fuente
1

Bash + GNU utils, 41

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

La cadena se ingresa a través de STDIN, el ancho se ingresa mediante la línea de comandos arg:

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

Python 2, 151 bytes

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

Esta es una adaptación de la respuesta de @ xnor anterior, ya que la suya no maneja correctamente las nuevas líneas.


El forbucle fue cambiado de:

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

a:

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

Ejemplo

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


Puzzl
   es

    &

 Code
 Golf
Puertas de Zach
fuente
1

C #, 143 bytes

(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 te permite hacer expresiones bastante retorcidas. GroupByes útil aquí, pero es una pena que no puedan crear sobrecargas de funciones tomando el índice.

Asignar la lambda a un Func<string, int, string> para ejecutarlo

Menos golfizado:

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))));
Carl Walsh
fuente
1

Groovy, 63 bytes

Devuelve la cadena correctamente alineada. No sabía que había una función padLeft (y padRight, padCenter) hasta ahora.

f={s,n->s.split("(?<=\\G.{$n})|\n")*.padLeft(n," ").join("\n")}
dbramwell
fuente
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;})}
martillo de lobo
fuente
1

Ceilán, 107

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

Matlab, 99 bytes

¡Gracias a @beaker por eliminar 6 bytes!

Uso y función anónima:

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

Defina la función y use anspara llamarla:

>> @(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
Luis Mendo
fuente
1

Burlesque, 28 bytes

Igual que la versión siguiente, pero trata la línea 1 como el número y las otras líneas como la cadena.

lng_riPpun{pPco{pP' lp}mu}Wl

Uso como en:

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

Versión anterior (16 bytes):

{5co{5' lp}mu}Wl

Ejemplo:

blsq ) "Programming\nPuzzles\n&\nCode\nGolf"{5co{5' lp}mu}Wl
Progr
ammin
    g
Puzzl
   es
    &
 Code
 Golf
mroman
fuente