为问题所写的方法编写方法,需要找到特定左括号的第n次出现的索引(由用户定义,即如果用户提供带有附加参数'{'和'5'的字符串,将找到第5次出现,与'('和'[')相同。
目前正在使用while循环并比较每个字符,但这看起来很难看并且不是很有趣,有没有办法用正则表达式做到这一点?你能在正则表达式中使用变量吗?
<input type='text' class='show_invalid'/>
答案 0 :(得分:3)
需要字符串中给定字符的n
实例的偏移量,如果字符串包含少于nil
个字符的实例,则为n
。我会给出三个解决方案。第一个使用正则表达式,另外两个不使用。
chr = "("
str = "a(b(cd((ef(g(hi("
n = 5
使用正则表达式
chr_esc = Regexp.escape(chr)
#=> "\\("
r = /
\A # match the beginning of the string
(?: # begin a non-capture group
.*? # match zero or more characters lazily
#{chr_esc} # match the given character
) # end the non-capture group
{#{n-1}} # perform the non-capture group `n-1` times
.*? # match zero or more characters lazily
#{chr_esc} # match the given character
/x # free-spacing regex definition mode
#=> /
\A # match the beginning of the string
(?: # begin a non-capture group
.*? # match zero or more characters lazily
\( # match the given character
) # end the non-capture group
{4} # perform the non-capture group `n-1` times
.*? # match zero or more characters lazily
\( # match the given character
/x
str =~ r
#=> 0
$~.end(0)-1
#=> 10
对于最后一行,我们可以改写
Regexp.last_match.end(0)-1
请参阅Regexp::last_match,MatchData#end和String#index。
正则表达式通常是按如下方式编写的(即非自由间隔模式)。
/\A(?:.*?#{chr_esc}){#{n-1}}.*?#{chr_esc}/
将字符转换为偏移,删除不匹配字符的偏移量并返回剩余字符的n
偏移量
str.size.times.select { |i| str[i] == chr }[n-1]
#=> 10
n = 20
str.size.times.select { |i| str[i] == chr }[n-1]
#=> nil
s = str.dup
n.times.reduce(0) do |off,_|
i = s.index(chr)
break nil if i.nil?
s = s[i+1..-1]
off + i + 1
end - 1
#=> 10