避江


48

背景

在排版中,河流是一块文本中的视觉间隙,这是由于空间的同时对齐而发生的。这些特别令人讨厌,因为您的大脑似乎在周围视力中更容易拾取它们,从而不断分散您的视线。

例如,以下面的文本块为例,这些行的折断使得行宽不超过82个字符

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.

右下角有一条横跨六行的河流,在以下块中已突出显示:

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.

我们可以通过选择稍有不同的列宽来缓解这种情况。例如,如果我们使用不超过78个字符的行来布局相同的文本,则河的长度不得超过两行:

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.

请注意,出于这个问题的目的,我们仅考虑等宽字体,以使河流只是空间的垂直列。一条河的长度就是它所跨越的线数。

另外:如果您对比例字体的河流检测感兴趣 ,那么网络上会有一些有趣的帖子

挑战

您将得到一串可打印的ASCII字符(代码点0x20至0x7E)-即一行。打印此文本,其行宽在70到90个字符(含)之间,以使文本中任何河流的最大长度最小。如果有多个相同的(最小)最大河流长度的文本宽度,请选择较窄的宽度。上面带有78个字符的示例是该文本的正确输出。

若要换行,应使用换行符替换空格字符(0x20),以使生成的行具有尽可能多的字符,但不超过所选文本宽度。请注意,产生的换行符本身不属于该计数。例如,在上面的最后一个块中,Lorem[...]tempor包含78个字符,这也是文本的宽度。

您可以假定输入将不包含连续的空格,并且将不包含前导或尾随空格。您可能还假定没有一个单词(非空格的连续子字符串)包含超过70个字符。

您可以编写程序或函数,通过STDIN,命令行参数或函数参数获取输入并将结果打印到STDOUT。

这是代码高尔夫球,因此最短的答案(以字节为单位)获胜。


我认为在您的78和82列换行示例中,最后一行和倒数第二行是不正确的。在82个示例中,最后一个中断应该在idest之间,而在78 个示例中,最后一个中断应该在inculpa之间。还是我做错了什么?
Cristian Lupascu 2014年

@Optimizer抢七是文字长度,而不是河流长度。
FryAmTheEggman 2014年

我猜这并不算是正式河流,但在示例中,最大长度为78个字符,在最左上角区域似乎有一条相当长的对角河
markasoftware 2014年

我们是否认为像这样的情况仍在继续?
Optimizer

巨大的挑战!嗯,下一个可能是关于河流(不是完全垂直的)塑造潜意识字母的意思;)
Tobias Kienzler 2014年

Answers:


7

CJam,116106 99 84 77 72字节

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

接受单行输入并将正确的输出打印到STDOUT。

更新:通过进行排序循环本身中的所有计算,做了很多改进并删除了多余的循环。还修复了河流长度计算中的错误。

尽快说明(在我进一步打高尔夫球之后)

在这里尝试


@Optimizer不过,您可以使用ARGV的输入,ea~而不是X每次都可以。保存两个字节。
Martin Ender 2014年

12

红宝石162 160 158 152 160 157(演示

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

非高尔夫版本:

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{...}允许我使用字符串插值。我刚刚尝试过21.times,但是它在以后会带来更多的影响,而且我还没有找到一个更短的解决方案。
Cristian Lupascu 2014年

@MartinBüttner是的,它确实有效!我已经编辑了答案。谢谢!
Cristian Lupascu 2014年


@Joshpbarron非常好发现!我现在修复了。
Cristian Lupascu 2014年

8

APL(105)

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

说明:

  • (K⊂⍨' '=K←' ',⍵):在前面添加一个空格,然后在这些空格上分割。每个单词保留其开头的空间。
  • ∘{... }¨70+⍳21:使用该值,表示范围内的每个数字[71, 91]:(由于单词的分割方式,每个“行”以开头都有一个多余的空格,以后将删除该空格。范围会移动一个以补偿额外的空间。)
    • ×⍴⍺::如果还有话要说,
      • z←⍵>+\≢¨⍺:获取每个单词的长度,并计算每个单词的长度总和。标记1所有可以填满下一行的单词,并将其存储在中z
      • (⊂z/⍺),⍵∇⍨⍺⍨~z:用这些词,然后处理列表中剩下的内容。
    • ⋄⍺:如果没有,则返回(现在为空)。
  • G←:存储行列表G(每行可能的长度为一个)。
  • V←{... }¨G:针对每种可能性,计算最长河流的长度并将其存储在V
    • +\↑≢¨¨⍵:再次获得每个单词的长度,并根据长度创建一个矩阵。计算矩阵行中每一行的运行总计。(因此,每行开头的多余空格将被忽略。)
    • 2≠⌿:对于矩阵的每一,请查看该点的当前行长度是否与该行之后的行不匹配。如果是这样,那儿就没有河了。
    • ⊂⍨¨↓⍉:将矩阵的每一列本身(在1s上)分开。这给出了一个列表列表,其中每条河流都有一个列表[1, 0, 0, ...],具体取决于河流的长度。如果没有河流,则清单为[1]
    • ⌈/≢¨:获取每条河的长度,并获取最大值。
  • ⊃G/⍨V=⌊/V:从中G,选择第一个项目,其最长河流的长度等于所有项目的最小长度。
  • {1↓∊⍵,3⊃⎕TC}¨:对于每一行,将所有单词连接在一起,删除第一项(开头处多余的空格),并在末尾添加换行符。
  • :将所有行连接在一起。

这是200个字节,而不是105
user11153

3
@ user11153我尚未将UTF-8指定为编码。APL字符集适合单个代码页(并且该代码页存在),即存在现有编码,通过这些编码,每个字符都适合一个字节,因此105完全可以。
Martin Ender 2014年

很高兴知道!:)
user11153 2014年

8

Bash + coreutils,236 157字节

使用不同的方法进行编辑-比以前短了很多:

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

从命令行读取输入字符串。

通过3种嵌套排序,我不禁思索big-O时间的复杂性是什么,但是它确实在我的机器上不到10秒的时间内完成了示例。


3

Python,314个字节

非常感谢SP3000,grc和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-thon
Optimizer

3

的JavaScript(ES6)194 202

迭代解决方案,如果递归的话可能会更短

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

讲解

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

在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.')

输出量

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个字节

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

非高尔夫版本:

# 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)]))
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.