我几天都在考虑这个问题,而且我无法找到适合我生活的优雅解决方案。
在我的应用中,我有一个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
我尝试过的所有事情都涉及到一些愚蠢的复杂条件和复杂的临时变量,我觉得这里有一个更简单的解决方案。
答案 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