Allinea il testo a destra


27

Il tuo compito è prendere un input di stringa e un numero e allineare la stringa a destra, rendendo la larghezza del testo il numero. Quando una linea è troppo lunga, spezzala e metti il ​​resto sulla riga successiva, ripetendo fino a quando non è necessario. Se una linea è più corta della larghezza, riempila di spazi. Possono comparire più righe e devono essere trattate come qualsiasi altro carattere singolo.

Ad esempio, la stringa

Programming
Puzzles
&
Code
Golf

e il numero 5produrrebbe:

Progr
ammin
    g
Puzzl
   es
    &
 Code
 Golf

Considerando che la stessa stringa e il numero 10produrrebbe:

Programmin
         g
   Puzzles
         &
      Code
      Golf

La stringa

a

b

e il numero 5 produrrebbe:

    a
      <-- note the 5 spaces
    b

Vince il codice più corto!


1
Il testo dice "Rompere le linee quando necessario [...]", ma i tuoi esempi suggeriscono che rompi dopo ogni parola, anche quando si adatterebbe. Si prega di chiarire: posizioniamo ogni parola su una nuova riga o implementiamo un vero algoritmo di avvolgimento delle parole?
Timwi,

Possono esserci spazi nel mezzo di una linea di input, ad esempio Programming Puzzles\n&\nCode Golf?
Sp3000,

@ sp3000 Può esserci qualsiasi carattere, inclusi gli spazi.
Trebuchette,

@Timwi: l'esempio ha una parola per riga. Sarebbe stato meglio includere alcune righe di più parole per chiarire che lo spazio all'interno di una riga non è speciale. (cioè ci sono solo newline e non newline.)
Peter Cordes,

Risposte:



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

Accetta come input una stringa con nuove righe e un numero e stampa il risultato. Per ogni riga nell'input, prende e stampa i ncaratteri alla volta, usando l'integrato rjustper riempire gli spazi di sinistra prima di stampare.

Ho risolto il caso della riga vuota con l'hack w=w or' '. Probabilmente c'è un metodo migliore ma non ci penserò molto.


8

CJam, 21 byte

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

Grazie a @ Sp3000 per giocare a golf a 1 byte e spianare la strada per altri 3.

Provalo online nell'interprete CJam .

Come funziona

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

Provalo online qui

Spiegazione

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 byte

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

36 byte + 3 byte per -ni. La larghezza di avvolgimento viene passata come argomento a -i.

Gestisce correttamente le righe vuote riempendole di spazi:

$ 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

Come funziona

Questa soluzione utilizza l'operatore di sostituzione per eseguire il ciclo dell'ingresso, salvando un byte sul forcircuito equivalente . Il vero trucco, tuttavia, è nella regex sull'LHS della sostituzione:

^$|.{1,$^I}

Con il modificatore globale, questo abbinerà i $^Icaratteri alla volta; quando $^Inella stringa restano meno caratteri, corrisponderà a tutto fino alla fine. L'alternanza con ^$è necessaria per gestire le righe vuote. Per esempio:

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

L'RHS della sostituzione utilizza semplicemente il printfpad sinistro del pad abbinato con spazi.


Mi dimentico sempre di $^I!
Dom Hastings,

@DomHastings Ho imparato quel trucco da chilemagic, che lo ha menzionato in un commento su un'altra sfida .
ThisSuitIsBlackNon

3

Javascript (ES6), 107

Vorrei che JS avesse una funzione pad integrata. Oh bene.

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

Spiegazione:

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

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

Più breve se Npuò essere impostato dal chiamante, invece di doverlo leggere come prima riga di input.

# 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

Questo non riesce a gestire le righe vuote nell'input. Altrimenti, ciò non sottopone i dati di input a suddivisione di parole, espansione del percorso o altrimenti non li considera più di semplici dati non elaborati.

read -n$Nsalva un personaggio, ma lascia readmunge \.

Il [[ $r ]]&&è necessario perché read -n4non può lookahead di vedere che il prossimo char è un ritorno a capo. Quindi si imposta rsu una stringa di 4 caratteri e la lettura successiva produce una stringa vuota di zero caratteri. Filtrare queste false newline senza filtrare le newline reali richiederebbe lo stato di tracciamento: se la linea precedente era di lunghezza massima o meno. Sarebbe necessario più codice o un approccio totalmente diverso.

[[ $r ]]è più corto di quello [ -n "$r" ]necessario per evitare errori se la linea inizia con -z foo, o è *o qualcosa del genere, se è stata utilizzata [ $r ].

La giustizia si verifica con la stringa di formato standard "% 4s" di printf.

Prova con

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

1. Includerei -rnel conteggio dei byte. 2. f()(while ... done)è un po 'più corto.
Dennis,

@Dennis: Senza [[ $r ]]&&, se N = 4, una linea di input di lunghezza 4 produrrà una linea di output vuota dove prima non ce n'era una. Perché readrestituisce una stringa di 4 caratteri, quindi vede una nuova riga alla chiamata successiva e ritorna immediatamente. Inoltre, grazie per il ()suggerimento. Non sapevo che avresti potuto definire le fn in quel modo.
Peter Cordes,

Consiglio di leggere Suggerimenti per giocare a golf a Bash . È una grande risorsa.
Dennis,

In realtà, dato che whileè già composto, non hai nemmeno bisogno delle parentesi:f()while ... done
Dennis

@Dennis: wow, haxx. Grazie per il link Un paio di quelle cose erano nuove per me, e ho risolto un paio di cose in un'altra risposta :) Normalmente non gioco a golf, ma> 15 anni di essere un drogato della riga di comando mi hanno insegnato una cosa o due :)
Peter Cordes,

2

Haskell, 108 byte

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

Esempio di utilizzo:

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

    b
   cd
Matam
orpho
  sis

Come funziona

                              .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}}/^$/')

Usare bash per inserire il conteggio nel programma awk è prob. più piccolo della lettura con un NR==1{N=$0}blocco.

Leggi una riga alla volta. Dividi in blocchi di massimo 4 personaggi, usando FPAT. (corrisponde ai campi, anziché ai separatori. Estensione GNU.) Stampa ogni campo separatamente. (ORS predefinito = \ n).

La /^$/regola è lì per stampare righe vuote, che hanno NF = 0 e quindi non stampano affatto nell'altro blocco. Quindi, a differenza della mia soluzione pure-bash, questo funziona davvero nel caso generale.

Non correlato, ma la mia idea finora per perl è di 112 caratteri solo per il codice 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.=$_;}}'

Questo mangia una delle nuove linee ed è troppo lungo. $/=\1legge un byte alla volta. Aggiungiamo a $ l. Probabilmente una linea alla volta con un approccio split a larghezza fissa sarebbe più breve.


1

Utilità Bash + GNU, 41

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

La stringa viene immessa tramite STDIN, la larghezza viene immessa dalla riga di comando arg:

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

1

Python 2, 151 byte

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

Questo è un adattamento della risposta di @ xnor sopra, in quanto la sua non gestisce correttamente le nuove righe.


Il forloop è stato cambiato da:

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

Esempio

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


Puzzl
   es

    &

 Code
 Golf

1

C #, 143 byte

(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 ti consente di creare espressioni piuttosto nodose. GroupByè utile qui, ma è un peccato che non siano riusciti a creare sovraccarichi di funzioni prendendo l'indice.

Assegna il lambda a a Func<string, int, string>per eseguirlo

Meno 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 byte

Restituisce la stringa correttamente assegnata. Fino ad ora non sapevo che esistesse una funzione padLeft (e 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

Ceylon, 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 byte

Grazie a @beaker per la rimozione di 6 byte!

Utilizzo e funzione anonima:

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

Definire la funzione e utilizzare ansper chiamarla:

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

Come la versione seguente, ma considera la riga 1 come il numero e le altre righe come la stringa.

lng_riPpun{pPco{pP' lp}mu}Wl

Utilizzo come in:

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

Vecchia versione (16 byte):

{5co{5' lp}mu}Wl

Esempio:

blsq ) "Programming\nPuzzles\n&\nCode\nGolf"{5co{5' lp}mu}Wl
Progr
ammin
    g
Puzzl
   es
    &
 Code
 Golf
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.