如何在Ruby中使用省略号来缩短文件路径?

时间:2019-06-04 04:19:26

标签: ruby string path truncate

在Ruby(不是Rails)中,是否有一种直接的方法来获取长文件路径,并用省略号替换它的不重要部分,以使其显示更短?

例如:

  

一个/非常/长/路径/带有/很多/的/字符/那个/不会/适合/在/我/屏幕/容易地

成为类似这样的东西

  

一个/非常/低... /屏幕/轻松

我需要能够指定最大长度;并且路径的起点和终点应始终可见。

如果我将头撞到足够长的时间,我可能会找到解决方案,但是也许有人知道一种方法?

2 个答案:

答案 0 :(得分:2)

我使用了左右指针(lt_ptrrt_ptr)来构建字符串的这两部分,该部分将保留并用省略号分隔。

我首先减少指向最后一个正斜杠的右指针,然后增加指向第一个正斜杠的左指针,然后减少指向倒数第二个正斜杠的右指针,依此类推,直到指针进一步移动为止。指针会使包含省略号的字符串长于最大允许长度。

代码

def shorten_string(str, max_len, ellipsis = '...')
  return str if str.size <= max_len
  max_len -= ellipsis.size
  ops = [{ index: :index, ptr: 0, chg: 1 },
         { index: :rindex, ptr: str.size-1, chg: -1 } ].cycle
  op = ops.next
  success = true
  loop do
    op = ops.next
    ptr = str.public_send(op[:index], '/', op[:ptr] + op[:chg] )
    lptr = ptr
    rptr = ops.peek[:ptr]
    lptr, rptr = rptr, lptr if op[:index] == :rindex
    if lptr + 1 + str.size - rptr <= max_len
      op[:ptr] = ptr
    else
      break unless success
      success = false
    end        
  end
  op = ops.next if op[:index] == :rindex
  "%s%s%s" % [str[0..op[:ptr]], ellipsis, str[ops.peek[:ptr]..-1]]
end

示例

str = 'a/very/long/path/with/too/many/characters/to/fit/on/my/screen/easily'

shorten_string(str, 40)
  #=> "a/very/long/path/.../on/my/screen/easily" (length: 40)
shorten_string(str, 30)
  #=> "a/very/.../on/my/screen/easily"           (length: 30)
shorten_string(str, 20)
  #=> "a/.../screen/easily"                      (length: 19) 

在前两个示例中,所得到的字符串的长度(带省略号)与最大长度max_length完全相等,这当然是偶然的。请注意,在第二个示例中,省略号后面有4个正斜杠,而前面只有2个。这是因为在添加"/my"之后,只能再添加3个字符,对于"long/"(紧随"very/"之后的字符来说,这还不够,但是对于"/on"来说,这是足够的。

说明

这使用String#index和[String#rindex](http://ruby-doc.org/core- 2.5.1 / String.html#method-i-rindex)使用第二个参数。

为了更好地理解正在执行的计算,我建议在用puts语句添加代码之后,针对一个示例运行该代码。修改后的方法的示例如下。

def shorten_string(str, max_len, ellipsis = '...')
  return str if str.size <= max_len
  max_len -= ellipsis.size
  puts "str.size=#{str.size}"                                   #!!!!
  ops = [{ index: :index, ptr: 0, chg: 1 },
         { index: :rindex, ptr: str.size-1, chg: -1 } ].cycle
  op = ops.next
  success = true
  loop do
    op = ops.next
    puts "\nop=#{op}, ops.peek=#{ops.peek}"                     #!!!!
    ptr = str.public_send(op[:index], '/', op[:ptr] + op[:chg] )
    lptr = ptr
    rptr = ops.peek[:ptr]
    puts "ptr=#{ptr}, lptr=#{lptr}, rptr=#{rptr}"               #!!!!
    lptr, rptr = rptr, lptr if op[:index] == :rindex
    puts "after possible flip, lptr=#{lptr}, rptr=#{rptr}"      #!!!!
    puts "lptr + 1 + str.size - rptr = #{lptr+1+str.size-rptr}" #!!!!
    if lptr + 1 + str.size - rptr <= max_len
      op[:ptr] = ptr
      puts "after lptr+1+str.size-rptr <= max_len, op=#{op}"    #!!!!
    else
      break unless success
      success = false
    end        
  end
  puts "after loop op=#{op}, ops.peek=#{ops.peek}"              #!!!!
  op = ops.next if op[:index] == :rindex
  "%s%s%s" % [str[0..op[:ptr]], ellipsis, str[ops.peek[:ptr]..-1]]
end

答案 1 :(得分:1)

有点像:

shortener = ->(path, length) {
  l = length / 2 - 1
  [path[0...l], path[-l..-1]].join('..')
}
shortener.(path, 10)
#⇒ "a/ve..sily"