在 Ruby 中查找第 n 次出现的变量正则表达式?

use*_*064 1 ruby regex

为问题所说的内容编写一个方法,需要找到特定左括号第 n 次出现的索引(由用户定义,即如果用户提供带有附加参数 '{' 和 '5' 的字符串,它将找到这是第五次出现,与“(”和“[”)相同。

目前使用 while 循环来比较每个字符,但这看起来很难看并且不是很有趣,有没有办法用正则表达式来做到这一点?可以在正则表达式中使用变量吗?

def _find_bracket_n(str,left_brac,brackets_num)
  i = 0
  num_of_left_bracs = 0
  while i < str.length && num_of_left_bracs < brackets_num
    num_of_left_bracs += 1 if str[i] == left_brac
    i += 1
  end
  n_th_lbrac_index = i - 1
end
Run Code Online (Sandbox Code Playgroud)

Car*_*and 5

n需要字符串中给定字符的第 th 个实例的偏移量,或者nil字符串包含的实例少于n该字符的实例。我将给出四种解决方案。

chr = "("
str = "a(b(cd((ef(g(hi(" 
n = 5
Run Code Online (Sandbox Code Playgroud)

使用枚举#find_index

str.each_char.find_index { |c| c == chr && (n = n-1).zero? }
  #=> 10
Run Code Online (Sandbox Code Playgroud)

使用正则表达式

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
Run Code Online (Sandbox Code Playgroud)

对于最后一行我们可以写

Regexp.last_match.end(0)-1
Run Code Online (Sandbox Code Playgroud)

请参阅Regexp::escapeRegexp::last_matchMatchData#end

正则表达式按照常规方式(即非自由间距模式)编写如下。

/\A(?:.*?#{chr_esc}){#{n-1}}.*?#{chr_esc}/
Run Code Online (Sandbox Code Playgroud)

将字符转换为偏移量,删除不匹配字符的偏移量并返回n剩余字符的第 th 个偏移量

str.size.times.select { |i| str[i] == chr }[n-1]
  #=> 10
n = 20
str.size.times.select { |i| str[i] == chr }[n-1]
  #=> nil
Run Code Online (Sandbox Code Playgroud)

重复使用String#index来截断子字符串

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
Run Code Online (Sandbox Code Playgroud)