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.