我有一个字符串a5bc2cdf3
。我想将其扩展为aaaaabcbccdfcdfcdf
。
在字符串中为a5
,因此结果字符串应包含5个连续的“a”s,“bc2”导致“bc”连续出现2次,而cdf
应重复{{1}时间。
如果输入为3
,输出为a5bc2cdf3
,我该如何在Ruby方法中执行此操作?
aaaaabcbccdfcdfcdf
答案 0 :(得分:3)
您可以使用像
这样的正则表达式.gsub(/([a-zA-Z]+)(\d+)/){$1*$2.to_i}
/([a-zA-Z]+)(\d+)/
将匹配带有1个以上字母(([a-zA-Z]+)
)和1+个数字((\d+)
)的存根串,并将它们捕获为2个组,这些组稍后在块内使用以返回你需要的字符串。
请注意,您可以考虑使用可以匹配任何字母的[a-zA-Z]
代替\p{L}
。
一旦在原始"压缩"中达到指定的索引,您想要突破gsub
串。仍有可能,请参阅this Ruby demo:
s = 'a5bc2cdf3' # input string
index = 5 # break index
result = "" # expanded string
s.gsub!(/([a-zA-Z]+)(\d+)/){ # regex replacement
result << $1*$2.to_i # add to the resulting string
break if Regexp.last_match.end(0) >= index # Break if the current match end index is bigger or equal to index
}
puts result[index] # Show the result
# => b
为简洁起见,您可以将Regexp.last_match
替换为$~
。
答案 1 :(得分:2)
我建议使用scan
移动压缩字符串,使用一个简单的RegEx来检测非十进制字符组,然后将它们计为十进制/([^\d]+)(\d+)/
。
def get_character(compressed_string, index)
result = nil
compressed_string.scan(/([^\d]+)(\d+)/).inject(0) do |total_length, (chars, count)|
decoded_string = chars * count.to_i
total_length += decoded_string.length
if index < total_length
result = decoded_string[-(total_length - index)]
break
else
total_length
end
end
result
end
知道当前(总)长度,如果当前扩展字符串包括所请求的索引,则可以突破循环。该字符串永远不会完全解码。
此代码提供以下结果
get_character("a5bc2cdf3", 5) # => "b"
get_character("a5bc2cdf3", 10) # => "d"
get_character("a5bc2cdf3", 20) # => nil
答案 2 :(得分:0)
另一种方式。我很喜欢Wiktor的方法。
def stringy str, index
lets, nums = str.split(/\d+/), str.split(/[a-z]+/)[1..-1].map(&:to_i)
ostr = lets.zip(nums).map { |l,n| l*n }.join
ostr[index]
end
str = 'a5bc2cdf3'
p stringy str, 5 #=> "b"
答案 3 :(得分:0)
我使用:
str.split(/(\d+)/) # => ["a", "5", "bc", "2", "cdf", "3"]
以下是它如何分解:
split
这是有效的,因为/(\d+)/
会返回正在分割的值,如果它在正则表达式组中:str.split(/(\d+)/).each_slice(2).to_a # => [["a", "5"], ["bc", "2"], ["cdf", "3"]]
。
each_slice(2)
可以使用str.split(/(\d+)/).each_slice(2).map { |s, c| s * c.to_i } # => ["aaaaa", "bcbc", "cdfcdfcdf"]
将生成的数组分解为要重复的字符串及其关联计数。
map
然后可以在使用String *
的{{1}}中处理该数组数组,以重复这些字符。
最后join
将所有生成的扩展字符串连接成一个字符串。