我如何正则表达式匹配未知数量的重复元素?

时间:2016-08-03 07:58:48

标签: ruby regex gsub

我正在尝试编写一个Ruby脚本,用一个等价的px替换CSS文件中的所有rem值。这将是一个示例CSS文件:

body{font-size:1.6rem;margin:4rem 7rem;}

我想得到的MatchData将是:

#    Match 1           Match 2
#    1. font-size      1. margin
#    2. 1.6            2. 4
#                      3. 7

然而,我完全不知道如何获得多个不同的MatchData结果。让我最接近的RegEx就是这个(you can also take a look at it at Rubular):

/([^}{;]+):\s*([0-9.]+?)rem(?=\s*;|\s*})/i

这将匹配值声明的单个实例(因此它将正确返回所需的Match 1结果),但完全忽略了倍数。

我也尝试了([0-9.]+?rem\s*)+的某些内容,但这并没有返回所需的结果,也不觉得我在正确的轨道上,因为它不会返回多个结果数据集。

编辑在答案中的建议之后,我最终解决了这样的问题:

# search for any declarations that contain rem unit values and modify blockwise
@output.gsub!(/([^ }{;]+):\s*([^}{;]*[0-9.]rem+[^;]*)(?=\s*;|\s*})/i) do |match|
  # search for any single rem value
  string = match.gsub(/([0-9.]+)rem/i) do |value|
    # convert the rem value to px by multiplying by 10 (this is not universal!)
    value = sprintf('%g', Regexp.last_match[1].to_f * 10).to_s + 'px'
  end
  string += ';' + match # append the original match result to the replacement
  match = string # overwrite the matched result
end

4 个答案:

答案 0 :(得分:1)

您无法捕捉动态数量的匹配组(至少不是红宝石)。

相反,您可以执行以下任一操作:

  1. 捕获整个值并拆分空间
  2. 使用多级匹配首先捕获整个键/值对,然后匹配该值。您可以在ruby中使用match方法中的块。

答案 1 :(得分:0)

这个正则表达式将为你的例子做好准备:

([^}{;]+):(?:([0-9\.]+?)rem\s?)?(?:([0-9\.]+?)rem\s?)

但是这样你就不能匹配:margin:4rem 7rem 9rem

答案 2 :(得分:0)

这就是我能够做到的:DEMO

正则表达式:(?<={|;)([^:}]+)(?::)([^A-Za-z]+)

这就是我的结果:

 #    Match 1           Match 2
 #    1. font-size      1. margin
 #    2. 1.6            2. 4

正如@koffeinfrei所说,Ruby中的动态捕获是不可能的。更聪明的是捕获整个字符串并删除空格。

答案 3 :(得分:0)

str = 'body{font-size:1.6rem;margin:4rem 7rem;}'
str.scan(/(?<=[{; ]).+?(?=[;}])/)
   .map { |e| e.match /(?<prop>.+):(?<value>.+)/ }
#⇒ [
#    [0] #<MatchData "font-size:1.6rem" prop:"font-size" value:"1.6rem">,
#    [1] #<MatchData "margin:4rem 7rem" prop:"margin" value:"4rem 7rem">
# ]

后者match可能很容易适应您想要的任何内容,value.split(/\s+/)会返回所有值,\d+代替.+只会匹配数字等。< / p>