组成切片

时间:2014-12-05 22:46:55

标签: ruby slice

我几天都在考虑这个问题,而且我无法找到适合我生活的优雅解决方案。

在我的应用中,我有一个Text类,它只是String的包装:

class Text < Struct.new(:string, :style)
  def [](start, len)
    Text.new(string[start, len], style)
  end

  def length
    string.length
  end

  def to_s
   case style
   when :bold then "**" + string + "**"
   when :italic then "_" + string +"_"
   else string
   end
  end

  def inspect
    "<[#{style}] #{string}>"
  end
end

我还有一个Line类,它基本上是一个Text对象数组:

class Line < Struct.new(:texts)
  def [](start, len)
    # TODO Should return a new Line object.
  end

  def length
    texts.map(&:length).reduce(&:+)
  end

  def to_s
    texts.map(&:to_s).join
  end

  def inspect
    texts.map(&:inspect).join(" ")
  end
end

问题是,我如何在#[]中实施Line,以便它返回一个新的Line对象,其中&#34;正确&#34;切片包含的Text个对象?

这个想法是模仿String的切片行为。例如:

line = Line.new([Text.new("abcdef", :bold), Text.new("ghijkl", :default)])
puts line[0, 2]  # => **ab**
p    line[0, 2]  # => "<[:bold] ab>"
puts line[3, 6]  # => **def**ghi
p    line[3, 6]  # => "<[:bold] def> <[:default] ghi>"

请注意,Text对象的长度是其string成员的长度:

a = Text.new("abc", :bold)
puts a  # => **abc**
puts a.length  # => 3

Line对象的长度只是texts的长度之和:

line = Line.new([Text.new("abcdef", :bold), Text.new("ghijkl", :default)])
puts line.length  # => 12

我尝试过的所有事情都涉及到一些愚蠢的复杂条件和复杂的临时变量,我觉得这里有一个更简单的解决方案。

1 个答案:

答案 0 :(得分:0)

以下是可能对您有所帮助的摘录:

class Line

  def pos_to_index_and_offset(pos)
    raise ArgumentError if !texts or texts.empty?
    index = 0
    offset = pos
    while offset >= (size = texts[index].length)
      offset -= size
      index += 1
      raise ArgumentError if index > texts.length
    end
    return [index, offset]
  end

end