Éviter les rivières


48

Contexte

En typographie, les rivières constituent des lacunes visuelles dans un bloc de texte, dues à un alignement fortuit des espaces. Celles-ci sont particulièrement gênantes puisque votre cerveau semble les capter plus facilement en vision périphérique, ce qui distrait constamment vos yeux.

A titre d'exemple, prenons le bloc de texte suivant, lignes brisées de telle sorte que la largeur de ligne ne dépasse pas 82 caractères :

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.

Il y a une rivière qui s'étend sur six lignes dans la partie inférieure droite, que j'ai soulignée dans le bloc suivant:

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.

Nous pouvons atténuer cela en choisissant une largeur de colonne légèrement différente. Par exemple, si nous mettons en page le même texte en utilisant des lignes ne dépassant pas 78 caractères , il n'y a pas de rivière plus longue que deux lignes:

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.

Notez que pour les besoins de cette question, nous ne considérons que les polices à espacement fixe, telles que les rivières ne sont que des colonnes verticales d'espaces. La longueur d'une rivière est le nombre de lignes qu'elle couvre.

De plus: si vous êtes intéressé par la détection des rivières dans les polices proportionnelles, il existe des publications intéressantes sur le réseau.

Le défi

Vous recevez une chaîne de caractères ASCII imprimables (points de code 0x20 à 0x7E) - c’est-à-dire une seule ligne. Imprimez ce texte avec une largeur de trait comprise entre 70 et 90 caractères (inclus), de manière à minimiser la longueur maximale de tout cours d'eau dans le texte. S'il existe plusieurs largeurs de texte avec la même longueur maximale (minimale) de rivière, choisissez la largeur la plus étroite. L'exemple ci-dessus avec 78 caractères est la sortie correcte pour ce texte.

Pour rompre les lignes, vous devez remplacer les espaces (0x20) par des sauts de ligne, de sorte que les lignes résultantes contiennent autant de caractères que possible, mais pas plus que la largeur de texte choisie. Notez que le saut de ligne résultant ne fait pas partie de ce décompte. Par exemple, dans le dernier bloc ci-dessus, Lorem[...]temporcontient 78 caractères, ce qui correspond également à la largeur du texte.

Vous pouvez supposer que l'entrée ne contiendra pas d'espaces consécutifs et ne comportera pas d'espaces de début ou de fin. Vous pouvez également supposer qu'aucun mot (sous-chaîne consécutive de non-espaces) ne contiendra plus de 70 caractères.

Vous pouvez écrire un programme ou une fonction en prenant une entrée via STDIN, un argument de ligne de commande ou une fonction et en imprimant le résultat sur STDOUT.

C'est le code de golf, donc la réponse la plus courte (en octets) gagne.


Je pense que dans vos exemples d'encapsulation de colonne 78 et 82, la dernière et l'avant-dernière lignes sont incorrectes. Dans l'exemple 82, la dernière pause doit se situer entre id et est , et dans l'exemple 78, entre in et culpa . Ou est-ce que je fais quelque chose de mal?
Cristian Lupascu

@Optimizer Le paramètre décisif est la longueur du texte, pas la longueur de la rivière.
FryAmTheEggman

Je suppose que cela ne compte pas comme une rivière officielle, mais dans l'exemple, une longueur maximale de 78 caractères, il semble y avoir une assez longue rivière en diagonale dans la partie supérieure gauche de la gauche
Markasoftware

Est - ce que nous considérons comme des cas comme cela continue comme cours d' eau?
Optimiseur

Grand défi! Hm, on pourrait peut-être avoir des rivières (pas purement verticales) formant des lettres subliminales;)
Tobias Kienzler

Réponses:


7

CJam, 116 106 99 84 77 72 octets

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

Prend l'entrée d'une seule ligne et imprime la sortie correcte vers STDOUT.

UPDATE : Amélioré beaucoup et supprimé les boucles redondantes en effectuant tous les calculs dans la boucle de tri elle-même. Également corrigé un bug dans le calcul de la longueur de la rivière.

Explication bientôt (après avoir joué au golf encore plus loin)

Essayez-le ici


@Optimizer Vous pouvez utiliser l'entrée d'ARGV, vous pouvez le faire à la ea~place X. Enregistre deux octets.
Martin Ender

12

Ruby 162 160 158 152 160 157 ( démo )

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 version non-golfée:

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{...}me permet d'utiliser l'interpolation de chaîne. Je viens d'essayer 21.times, mais cela a d'autres implications sur la route et je n'ai pas réussi à trouver une solution plus courte.
Cristian Lupascu

@ MartinBüttner Vous avez raison, il fait le travail! J'ai édité ma réponse. Merci!
Cristian Lupascu

Cela ne fonctionne pas avec pastebin.com/vN2iAzNd
Joshpbarron

@Joshpbarron Très bien repéré! Je l'ai corrigé maintenant.
Cristian Lupascu

8

APL (105)

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

Explication:

  • (K⊂⍨' '=K←' ',⍵): Ajouter un espace devant , puis diviser les espaces. Chaque mot conserve l'espace avec lequel il commence.
  • ∘{... }¨70+⍳21: avec cette valeur, pour chaque nombre compris dans la plage [71, 91]: ((En raison de la façon dont les mots sont séparés, chaque "ligne" se termine par un espace supplémentaire au début, qui sera supprimé ultérieurement. La plage est décalée de un pour compenser l'espace supplémentaire.)
    • ×⍴⍺:: s'il reste des mots,
      • z←⍵>+\≢¨⍺: obtenez la longueur de chaque mot et calculez le total de la longueur par mot. Marquez avec 1tous les mots qui peuvent être utilisés pour remplir la ligne suivante et stockez-les dans z.
      • (⊂z/⍺),⍵∇⍨⍺⍨~z: prenez ces mots, puis traitez ce qui reste de la liste.
    • ⋄⍺: sinon, retourne (qui est maintenant vide).
  • G←: stocke la liste des listes de lignes dans G(une pour chaque longueur de ligne possible).
  • V←{... }¨G: pour chaque possibilité, calculez la longueur du plus long fleuve et stockez-la dans V:
    • +\↑≢¨¨⍵: récupère la longueur de chaque mot (encore) et crée une matrice à partir des longueurs. Calculez le total cumulé pour chaque ligne sur les lignes de la matrice. (Ainsi, l'espace supplémentaire au début de chaque ligne est ignoré.)
    • 2≠⌿: pour chaque colonne de la matrice, voir si la longueur actuelle de la ligne à ce point ne correspond pas à la ligne suivante. Si c'est le cas, il n'y a pas de rivière là-bas.
    • ⊂⍨¨↓⍉: divise chaque colonne de la matrice par elle-même (sur le 1s). Cela donne une liste de listes, où pour chaque rivière il y aura une liste [1, 0, 0, ...], en fonction de la longueur de la rivière. S'il n'y a pas de rivière, la liste sera [1].
    • ⌈/≢¨: obtenir la longueur de chaque rivière et en obtenir la valeur maximale.
  • ⊃G/⍨V=⌊/V: de G, sélectionnez le premier élément pour lequel la longueur de la plus longue rivière est égale au minimum pour tous les éléments.
  • {1↓∊⍵,3⊃⎕TC}¨: pour chaque ligne, associez tous les mots, supprimez le premier élément (l'espace supplémentaire du début) et ajoutez une nouvelle ligne à la fin.
  • : joindre toutes les lignes ensemble.

C'est 200 octets, pas 105.
user11153

3
@ user11153 Je n'ai pas spécifié UTF-8 comme encodage. Le jeu de caractères APL tient dans une seule page de code (et cette dernière existe ), c’est-à-dire qu’il existe un codage permettant à chacun de ces caractères de s’insérer dans un octet. Par conséquent, 105 convient parfaitement.
Martin Ender

Bon à savoir! :)
user11153

8

Bash + coreutils, 236 157 octets

Édité avec une approche différente - un peu plus courte qu'avant:

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

Lit la chaîne d'entrée à partir de la ligne de commande.

Avec 3 types imbriqués, je frémis de penser à la complexité du temps énorme pour cela, mais cela complète l'exemple en moins de 10 secondes sur ma machine.


3

Python, 314 octets

Un grand merci à SP3000, grc et 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
Plus comme Pi-thon
Optimizer

3

JavaScript (ES6) 194 202

Solution itérative, peut-être plus courte si rendue récursive

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

A expliqué

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

Testez dans la 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.')

Sortie

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 octets

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

Version non-golfée:

# 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)]))
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.