Alinhar à direita o texto


27

Seu trabalho é pegar uma entrada e um número de sequência e alinhar a sequência à direita, tornando a largura do texto o número. Quando uma linha for muito longa, quebre-a e coloque o restante na próxima linha, repetindo até que não seja necessário. Se uma linha for menor que a largura, preencha-a com espaços. Várias novas linhas podem ocorrer e devem ser tratadas como qualquer outro caractere único.

Por exemplo, a sequência

Programming
Puzzles
&
Code
Golf

e o número 5produziria:

Progr
ammin
    g
Puzzl
   es
    &
 Code
 Golf

Considerando que a mesma string e o número 10produziriam:

Programmin
         g
   Puzzles
         &
      Code
      Golf

A corda

a

b

e o número 5 produziria:

    a
      <-- note the 5 spaces
    b

O menor código vence!


1
O texto diz "Quebre as linhas quando necessário [...]", mas seus exemplos sugerem que você quebre após cada palavra, mesmo quando for adequado. Esclareça: colocamos cada palavra em uma nova linha ou implementamos um algoritmo de quebra de linha real?
— Timwi

Pode haver espaços no meio de uma linha de entrada, por exemplo Programming Puzzles\n&\nCode Golf?
— Sp3000 24/15

@ sp3000 Pode haver qualquer caractere, incluindo espaços.
— Trebuchette

@ Timwi: O exemplo tem uma palavra por linha. Teria sido melhor incluir algumas linhas com várias palavras para deixar claro que o espaço dentro de uma linha não é especial. (ou seja, não são apenas linhas novas, e não-novas linhas.)
— Pedro Cordes

Respostas:



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

Toma como entrada uma string com novas linhas e um número e imprime o resultado. Para cada linha da entrada, obtém e imprime ncaracteres de cada vez, usando o built-in rjustpara preencher a esquerda com espaços antes da impressão.

Corrigi o estojo da linha vazia com o hack w=w or' '. Provavelmente existe um método melhor, mas não vou pensar muito sobre isso.


8

CJam, 21 bytes

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

Graças ao @ Sp3000 por jogar 1 byte e abrir mais 3.

Experimente on-line no intérprete CJam .

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

5

Pyth, 16

jm>Q+*\ QdscRQ.z

Experimente online aqui

Explicação

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 bytes

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

36 bytes + 3 bytes para -ni. A largura da quebra é passada como argumento para -i.

Manipula linhas em branco corretamente preenchendo-as com espaços:

$ 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

Como funciona

Esta solução usa o operador de substituição para fazer um loop pela entrada, economizando um byte no forloop equivalente . O verdadeiro truque, no entanto, está na regex no LHS da substituição:

^$|.{1,$^I}

Com o modificador global, isso corresponderá a $^Icaracteres por vez; quando houver menos de $^Icaracteres restantes na sequência, ela corresponderá a tudo até o fim. A alternância com ^$é necessária para manipular linhas em branco. Por exemplo:

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

O RHS da substituição simplesmente usa printfpara deixar o bloco correspondente com espaços à esquerda.


Eu sempre esqueço $^I!
— Dom Hastings

@DomHastings Aprendi esse truque com o chilemagic, que o mencionou em um comentário sobre outro desafio .
— ThisSuitIsBlackNot

3

Javascript (ES6), 107

Eu gostaria que o JS tivesse uma função integrada no bloco. Ah bem.

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

Explicação:

(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 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

Ungolfed:

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+ , 59

Menor se Npuder ser definido pelo chamador, em vez de ter que lê-lo como a primeira linha 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

Isso falha ao manipular linhas vazias na entrada. Caso contrário, isso não sujeita os dados de entrada a divisão de nomes, expansão de nome de caminho ou os trata como mais do que apenas dados brutos.

read -n$Nsalva um personagem, mas deixa o readmunge \.

O [[ $r ]]&&é necessário, porque read -n4não podemos olhar para ver se o próximo caractere é uma nova linha. Portanto, ele define rcomo uma sequência de 4 caracteres e a próxima leitura produz uma sequência vazia de zero caractere. Filtrar essas novas linhas falsas sem filtrar novas linhas reais exigiria um estado de rastreamento: se a linha anterior era de tamanho máximo ou não. Seria necessário mais código ou uma abordagem totalmente diferente.

[[ $r ]]é menor do [ -n "$r" ]que o necessário para evitar erros se a linha começar com -z foo, ou for *ou algo assim, se você usou [ $r ].

A justificação ocorre com a sequência de formato padrão printf "% 4s".

Teste com

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

1. Eu incluiria -rna contagem de bytes. 2. f()(while ... done)é um pouco menor.
— Dennis

@ Dennis: Sem [[ $r ]]&&, se N = 4, uma linha de entrada de comprimento 4 produzirá uma linha de saída em branco onde não havia uma antes. Porque readretorna uma string de 4 caracteres, em seguida, vê uma nova linha na próxima chamada e retorna imediatamente. Além disso, obrigado pela ()dica. Eu não sabia que você poderia definir fns dessa maneira.
— 22615 Peter Cordes

Eu recomendo a leitura de dicas para jogar golfe no Bash . É um ótimo recurso.
— Dennis

Na verdade, como whilejá é composto, você nem precisa dos parênteses:f()while ... done
— Dennis

@Dennis: uau, haxx. Obrigado pelo link. Algumas dessas coisas eram novas para mim, e eu consertei algumas em outra resposta :) Normalmente não jogo golfe, mas> 15 anos como viciado em linha de comando me ensinaram uma coisa ou duas :)
— 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

Exemplo de uso:

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

    b
   cd
Matam
orpho
  sis

Como 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

1

GNU awk + bash, 70

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

Usar o bash para inserir a contagem no programa awk é prob. menor do que lê-lo com um NR==1{N=$0}bloco.

Leia uma linha de cada vez. Divida em pedaços com no máximo 4 caracteres, usando FPAT. (corresponde aos campos, em vez dos separadores. Extensão GNU.) imprime cada campo separadamente. (ORS padrão = \ n).

A /^$/regra existe para imprimir linhas vazias, que possuem NF = 0 e, portanto, não são impressas no outro bloco. Portanto, diferentemente da minha solução pura, isso realmente funciona no caso geral.

Semi-independente, mas minha ideia até agora para perl é de 112 caracteres apenas para o 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.=$_;}}'

Isso come uma das novas linhas e é muito longo. $/=\1lê um byte de cada vez. Anexamos a $ l. Provavelmente, uma linha de cada vez com uma abordagem de divisão de largura fixa seria mais curta.


1

Utilitários Bash + GNU, 41

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

A sequência é inserida via STDIN, a largura é inserida pela linha de comando arg:

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

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 é uma adaptação da resposta de @ xnor acima, pois a dele não lida adequadamente com novas linhas.


O forloop foi alterado de:

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

para:

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

Exemplo

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


Puzzl
   es

    &

 Code
 Golf

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

O Linq permite que você faça expressões bastante complicadas. GroupByé útil aqui, mas é uma pena que eles não tenham conseguido criar sobrecargas de função usando o índice.

Atribua o lambda a Func<string, int, string>para executá-lo

Menos golfe:

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 bytes

Retorna a string alinhada corretamente. Não sabia que havia uma função padLeft (e padRight, padCenter) até agora.

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

Ceilão, 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 bytes

Obrigado ao @beaker por remover 6 bytes!

Usando e função anônima:

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

Defina a função e use-a anspara chamá-la:

>> @(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

Burlesco, 28 bytes

Igual à versão abaixo, mas trata a linha 1 como o número e as outras linhas como a sequência.

lng_riPpun{pPco{pP' lp}mu}Wl

Uso como em:

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

Versão antiga (16 bytes):

{5co{5' lp}mu}Wl

Exemplo:

blsq ) "Programming\nPuzzles\n&\nCode\nGolf"{5co{5' lp}mu}Wl
Progr
ammin
    g
Puzzl
   es
    &
 Code
 Golf
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.