Как сократить пути к файлам с помощью эллипсов в Ruby? - PullRequest
0 голосов
/ 04 июня 2019

В Ruby (не Rails), есть ли простой способ взять длинный путь к файлу и заменить его неважные части на эллипсы, чтобы сделать его короче для отображения?

Например:

a / очень / длинный / путь / с / много / из / символов / которые / не будут / подходят / на / мой / экран / легко

Становится что-то вроде:

a / очень / lo ... / экран / легко

Мне нужно указать максимальную длину;и начало и конец пути всегда должны быть видны.

Возможно, я мог бы найти решение, если бы достаточно долго бился об него, но, возможно, кто-то знает способ?

Ответы [ 2 ]

2 голосов
/ 04 июня 2019

Я использовал левый и правый указатели (lt_ptr и rt_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 голос
/ 04 июня 2019

Примерно так:

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