Evitare i fiumi


48

sfondo

Nella tipografia, i fiumi sono vuoti visivi in ​​un blocco di testo, che si verificano a causa dell'allineamento casuale di spazi. Questi sono particolarmente fastidiosi poiché il tuo cervello sembra raccoglierli più facilmente nella visione periferica, che distrae costantemente i tuoi occhi.

Ad esempio, prendi il seguente blocco di testo, linee spezzate in modo tale che la larghezza della linea non superi gli 82 caratteri :

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eismod tempor
incididunt ut labore et dolore maga aliqua. Ut enim ad minim veniam, quis nostrud
exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute
irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui
officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet,
consectetur adipisicing elit, sed do eismod tempor incididunt ut labore et dolore
maga aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris
nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in
voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id
est laborum.

C'è un fiume che attraversa sei linee nella parte in basso a destra, che ho evidenziato nel seguente blocco:

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eismod tempor
incididunt ut labore et dolore maga aliqua. Ut enim ad minim veniam, quis nostrud
exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute
irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui
officia deserunt mollit anim id est laborum. Lorem█ipsum dolor sit amet,
consectetur adipisicing elit, sed do eismod tempor█incididunt ut labore et dolore
maga aliqua. Ut enim ad minim veniam, quis nostrud█exercitation ullamco laboris
nisi ut aliquip ex ea commodo consequat. Duis aute█irure dolor in reprehenderit in
voluptate velit esse cillum dolore eu fugiat nulla█pariatur. Excepteur sint
occaecat cupidatat non proident, sunt in culpa qui█officia deserunt mollit anim id
est laborum.

Possiamo mitigarlo scegliendo una larghezza di colonna leggermente diversa. Ad esempio, se impaginiamo lo stesso testo usando linee non più lunghe di 78 caratteri , non c'è fiume più lungo di due linee:

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eismod tempor
incididunt ut labore et dolore maga aliqua. Ut enim ad minim veniam, quis
nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore
eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt
in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor
sit amet, consectetur adipisicing elit, sed do eismod tempor incididunt ut
labore et dolore maga aliqua. Ut enim ad minim veniam, quis nostrud
exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis
aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
culpa qui officia deserunt mollit anim id est laborum.

Si noti che ai fini di questa domanda stiamo prendendo in considerazione solo i caratteri a spaziatura fissa, in modo che i fiumi siano semplicemente colonne verticali di spazi. La lunghezza di un fiume è il numero di linee che attraversa.

A parte: se sei interessante nel rilevamento del fiume in caratteri proporzionali, ci sono alcuni post interessanti nella rete.

La sfida

Ti viene data una stringa di caratteri ASCII stampabili (punti di codice da 0x20 a 0x7E), ovvero una singola riga. Stampa questo testo, con una larghezza della linea compresa tra 70 e 90 caratteri (incluso), in modo tale da ridurre al minimo la lunghezza massima di qualsiasi fiume nel testo. Se ci sono più larghezze di testo con la stessa (minima) lunghezza massima del fiume, scegli la larghezza più stretta. L'esempio sopra con 78 caratteri è l'output corretto per quel testo.

Per interrompere le linee, è necessario sostituire i caratteri di spazio (0x20) con le interruzioni di riga, in modo che le linee risultanti abbiano il maggior numero possibile di caratteri, ma non più della larghezza del testo scelta. Si noti che l'interruzione di riga risultante non fa parte di quel conteggio. Ad esempio, nell'ultimo blocco sopra, Lorem[...]temporcontiene 78 caratteri, che è anche la larghezza del testo.

Si può presumere che l'input non conterrà spazi consecutivi e non avrà spazi iniziali o finali. Puoi anche supporre che nessuna parola (sottostringa consecutiva di non spazi) conterrà più di 70 caratteri.

È possibile scrivere un programma o una funzione, prendendo l'input tramite STDIN, argomento della riga di comando o argomento della funzione e stampando il risultato su STDOUT.

Questo è il golf del codice, quindi vince la risposta più breve (in byte).


Penso che nei tuoi esempi di avvolgimento delle colonne 78 e 82, l'ultima e la penultima riga siano errate. Nell'esempio 82, l'ultima interruzione dovrebbe essere tra id ed est e nell'esempio 78 dovrebbe essere tra in e culpa . O sto facendo qualcosa di sbagliato?
Cristian Lupascu,

@Optimizer L'interruzione del pareggio è la lunghezza del testo, non la lunghezza del fiume.
FryAmTheEggman,

Immagino che non valga come un fiume ufficiale, ma nell'esempio con una lunghezza massima di 78 caratteri, sembra che ci sia un fiume abbastanza lungo in diagonale nella parte più a sinistra dell'area sinistra
markasoftware

Consideriamo casi come questo mentre continuano i fiumi?
Ottimizzatore

Grande sfida! Il prossimo potrebbe essere quello di avere fiumi (non puramente verticali) che modellano lettere subliminali;)
Tobias Kienzler,

Risposte:


7

CJam, 116 106 99 84 77 72 byte

l:X;93,72>{:D;OOXS/{S+_2$+,D<{+}{@@);a+\}?}/a+}%{z'K*S/:!0a/1fb$W=}$0=N*

Accetta l'ingresso a riga singola e stampa l'output corretto su STDOUT.

AGGIORNAMENTO : migliorato molto e rimosso i loop ridondanti eseguendo tutti i calcoli nel loop di ordinamento stesso. Risolto anche un bug nel calcolo della lunghezza del fiume.

Spiegazione presto (dopo averlo golf ulteriormente)

Provalo qui


@Optimizer Tuttavia, è possibile utilizzare input da ARGV, quindi è possibile eseguire ea~invece Xogni volta. Salva due byte.
Martin Ender,

12

Rubino 162 160 158 152 160 157 ( demo )

i=gets+' '
(69..s=r=89).map{|c|w=i.scan(/(.{1,#{c}}\S) /).flatten
m=(0..c).map{|i|w.map{|l|l[i]}+[?x]}.join.scan(/ +/).map(&:size).max
m<s&&(s=m;r=w)}
puts r

La versione senza golf:

input = gets+' '

result = ''

(69..smallest_max=89).each{|w|
  #split text into words of at most w characters
  wrap = (input+' ').scan(/(.{1,#{w}}\S) /).flatten

  #transpose lines and find biggest "river"
  max_crt_river = (0..99).map{|i| wrap.map{|l|l[i]} }.flatten.join.scan(/ +/).max_by(&:size).size

  if max_crt_river < smallest_max
    smallest_max = max_crt_river
    result = wrap.join ?\n
  end
}
puts result

@ MartinBüttner %r{...}mi permette di usare l'interpolazione di stringhe. Ho appena provato 21.times, ma ha alcune implicazioni in più lungo la strada e non sono riuscito a raggiungere una soluzione più breve.
Cristian Lupascu,

@ MartinBüttner Hai ragione, si fa il lavoro! Ho modificato la mia risposta. Grazie!
Cristian Lupascu,

Questo non funziona con pastebin.com/vN2iAzNd
Joshpbarron

@Joshpbarron Molto ben notato! L'ho risolto ora.
Cristian Lupascu,

8

APL (105)

{∊{1↓∊⍵,3⊃⎕TC}¨⊃G/⍨V=⌊/V←{⌈/≢¨⊂⍨¨↓⍉2≠⌿+\↑≢¨¨⍵}¨G←(K⊂⍨' '=K←' ',⍵)∘{×⍴⍺:(⊂z/⍺),⍵∇⍨⍺/⍨~z←⍵>+\≢¨⍺⋄⍺}¨70+⍳21}

Spiegazione:

  • (K⊂⍨' '=K←' ',⍵): Aggiungi uno spazio davanti , quindi dividi gli spazi. Ogni parola mantiene lo spazio con cui inizia.
  • ∘{... }¨70+⍳21: con quel valore, per ogni numero nell'intervallo [71, 91]: (A causa del modo in cui le parole sono divise, ogni "linea" finisce con uno spazio aggiuntivo all'inizio, che verrà rimosso in seguito. L'intervallo viene spostato di uno per compensare lo spazio extra.)
    • ×⍴⍺:: se ci sono ancora parole,
      • z←⍵>+\≢¨⍺: ottiene la lunghezza per ogni parola e calcola un totale parziale della lunghezza, per parola. Segna con 1tutte le parole che possono essere prese per riempire la riga successiva e memorizzale in z.
      • (⊂z/⍺),⍵∇⍨⍺⍨~z: prendi quelle parole e poi elabora ciò che resta dell'elenco.
    • ⋄⍺: in caso contrario, restituisce (che ora è vuoto).
  • G←: archivia l'elenco degli elenchi di righe in G(uno per ogni possibile lunghezza di riga).
  • V←{... }¨G: per ogni possibilità, calcola la lunghezza del fiume più lungo e conservalo in V:
    • +\↑≢¨¨⍵: ottieni la lunghezza di ogni parola (di nuovo) e crea una matrice dalle lunghezze. Calcola il totale parziale per ogni riga sulle righe della matrice. (Pertanto, lo spazio aggiuntivo all'inizio di ogni riga viene ignorato.)
    • 2≠⌿: per ogni colonna della matrice, vedere se la lunghezza corrente della linea in quel punto non corrisponde alla linea dopo di essa. Se è così, non c'è non è un fiume lì.
    • ⊂⍨¨↓⍉: dividere ciascuna colonna della matrice da sola (sulla 1s). Questo fornisce un elenco di elenchi, dove per ogni fiume ci sarà un elenco [1, 0, 0, ...], a seconda della lunghezza del fiume. Se non c'è fiume, l'elenco sarà [1].
    • ⌈/≢¨: ottieni la lunghezza di ogni fiume e ottieni il valore massimo di quello.
  • ⊃G/⍨V=⌊/V: da G, seleziona il primo oggetto per il quale la lunghezza del fiume più lungo è uguale al minimo per tutti gli oggetti.
  • {1↓∊⍵,3⊃⎕TC}¨: per ogni riga, unisci tutte le parole insieme, rimuovi l'elemento pugno (lo spazio extra dall'inizio) e aggiungi una nuova riga alla fine.
  • : unisci tutte le linee insieme.

Sono 200 byte, non 105.
user11153

3
@ user11153 Non ho specificato UTF-8 come codifica. Il set di caratteri APL si inserisce in una singola codepage (e quella codepage esiste ), ovvero esiste una codifica esistente mediante la quale ciascuno di quei caratteri si inserisce in un byte, e quindi 105 va perfettamente bene.
Martin Ender,

Buono a sapersi! :)
user11153

8

Bash + coreutils, 236 157 byte

Modificato con un approccio diverso - un po 'più breve di prima:

a=(`for i in {71..91};{
for((b=1;b++<i;));{
fold -s$i<<<$@|cut -b$b|uniq -c|sort -nr|grep -m1 "[0-9]  "
}|sort -nr|sed q
}|nl -v71|sort -nk2`)
fold -s$a<<<$@

Legge la stringa di input dalla riga di comando.

Con 3 tipi nidificati, rabbrividisco al pensiero di quale sia la complessità del big-O time per questo, ma completa l'esempio in meno di 10 secondi sulla mia macchina.


3

Python, 314 byte

Mille grazie a SP3000, grc e FryAmTheEggman:

b=range;x=len
def p(i):
 l=[];z=''
 for n in t:
  if x(z)+x(n)<=i:z+=n+' '
  else:l+=[z];z=n+' '
 return l+[z]*(z!=l[x(l)-1])
t=input().split();q=[]
for i in b(70,91):l=p(i);q+=[max(sum(x(l[k+1])>j<x(l[k])and l[k][j]is' '==l[k+1][j]for k in b(x(l)-1))for j in b(i))]
print(*p(q.index(min(q))+70),sep='\n')

2
Più come Pi-thon
Optimizer

3

JavaScript (ES6) 194 202

Soluzione iterativa, forse più breve se resa ricorsiva

F=s=>{
  for(m=1e6,b=' ',n=70;n<91;n++)
    l=b+'x'.repeat(n),x=r=q='',
    (s+l).split(b).map(w=>
      (t=l,l+=b+w)[n]&&(
        l=w,r=r?[...t].map((c,p)=>x<(v=c>b?0:-~r[p])?x=v:v,q+=t+'\n'):[]
      )
    ),x<m&&(o=q,m=x);
  alert(o)
}

spiegato

F=s=> {
  m = 1e9; // global max river length, start at high value
  for(n=70; n < 91; n++) // loop on line length
  {
    l=' '+'x'.repeat(n), // a too long first word, to force a split and start
    x=0, // current max river length
    q='', // current line splitted text
    r=0, // current river length for each column (start 0 to mark first loop)
    (s+l) // add a too long word to force a last split. Last and first row will not be managed
    .split(' ').map(w=> // repeat for each word 
      (
        t=l, // current partial row in t (first one will be dropped)
        (l += ' '+w)[n] // add word to partial row and check if too long
        &&
        (
          l = w, // start a new partial row with current word
          r=r? // update array r if not at first loop
          ( 
            q+=t+'\n', // current row + newline added to complete text 
            [...t].map((c,p)=>( // for each char c at position p in row t
              v = c != ' ' 
                ? 0 // if c is not space, reset river length at 0
                : -~r[p], // if c is space, increment river length
              x<v ? x=v : v // if current > max, update max
            ))
          ):[]  
        )  
      )
    )
    x < m && ( // if current max less than global max, save current text and current max
      o = q,
      m = x
    )
  }
  console.log(o,m)
}

Test nella console FireFox / FireBug.

F('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eismod tempor incididunt ut labore et dolore maga aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eismod tempor incididunt ut labore et dolore maga aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.')

Produzione

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eismod tempor
incididunt ut labore et dolore maga aliqua. Ut enim ad minim veniam, quis
nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore
eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt
in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor
sit amet, consectetur adipisicing elit, sed do eismod tempor incididunt ut
labore et dolore maga aliqua. Ut enim ad minim veniam, quis nostrud
exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis
aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
culpa qui officia deserunt mollit anim id est laborum.

3

Python 3, 329 byte

import re,itertools as s
def b(t,n):
 l=0;o=""
 for i in t.split():
  if l+len(i)>n:o=o[:-1]+'\n';l=0
  l+=len(i)+1;o+=i+' '
 return o
t=input();o={}
for n in range(90,69,-1):o[max([len(max(re.findall('\s+',x),default='')) for x in ["".join(i) for i in s.zip_longest(*b(t,n).split('\n'),fillvalue='')]])]=n
print(b(t,o[min(o)]))

Versione non golfata:

# Iterates over words until length > n, then replaces ' ' with '\n'
def b(t,n):
    l = 0
    o = ""
    for i in t.split():
        if l + len(i) > n:
            o = o[:-1] + '\n'
            l = 0
        l += len(i) + 1
        o += i + ' '
    return o

t = input()
o = {}
# range from 90 to 70, to add to dict in right order
for n in range(90,69,-1):
    # break text at length n and split text into lines
    temp = b(t,n).split('\n')
    # convert columns into rows
    temp = itertools.zip_longest(*temp, fillvalue='')
    # convert the char tuples to strings
    temp = ["".join(i) for i in temp]
    # findall runs of spaces, get longest run and get length
    temp = [len(max(re.findall('\s+',x),default='')) for x in temp]
    # add max river length as dict key, with line length as value
    o[max(temp)] = n

print(b(t,o[min(o)]))
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.