“ gsub”中的默认值

时间:2018-10-01 07:11:22

标签: arrays ruby gsub

我有一个看起来像这样的数组:

arr = [
  "---\n",
  ":date: 2018-07-31\n  :story_points: 4.0\n  :remaining_hours: 4.0\n ",
  ":date: 2018-08-01\n  :story_points:    \n  :remaining_hours: 4.0\n ",
  ":date: 2018-08-22\n  :story_points: 8.0\n  :remaining_hours: 0.0\n "
]

我想在各个数组中提取datestory_points的值。如果缺少story_points的值,则应提供"0.0"的默认值。输出应如下所示:

["2018-07-31", "2018-08-01", "2018-08-22"]
["4.0", "0.0", "8.0"]

我尝试了另一位用户在我先前的帖子中建议的以下操作:

arr.join.gsub(/(?<=:date: )\d{4}-\d{2}-\d{2}/).to_a
arr.join.gsub(/(?<=:story_points: )\d{1}.\d{1}/).to_a 

以上内容将给出:

["2018-07-31", "2018-08-01", "2018-08-22"]
["4.0", "8.0"]

我无法获取默认值。有人可以帮忙吗?

3 个答案:

答案 0 :(得分:1)

尝试以下代码:

arr[1..-1].map { |s| (s.match(/(?<=:story_points: )\d{1}.\d{1}/) || '0.0').to_s }
#=> ["4.0", "0.0", "8.0"]

答案 1 :(得分:0)

基于数组的单遍传递的基于正则表达式的替代解决方案:

arr = [
  "---\n",
  ":date: 2018-07-31\n  :story_points: 4.0\n  :remaining_hours: 4.0\n ",
  ":date: 2018-08-01\n  :story_points:    \n  :remaining_hours: 4.0\n ",
  ":date: 2018-08-22\n  :story_points: 8.0\n  :remaining_hours: 0.0\n "
]
dates = []
sp = []
rx = /:date:\s*(\d{4}-\d{2}-\d{2})\s*:story_points:\s*(\d+\.\d+)?/
arr.each { |x| x.scan(rx) { |m,n| dates << m; sp << (n || "0.0")  } }
# => dates: [ "2018-07-31", "2018-08-01", "2018-08-22" ]
# => sp: [ "4.0", "0.0", "8.0" ]

请参见Ruby demo

这里是Rubular demo

模式说明

  • :date:-文字:date:子字符串
  • \s*-超过0个空格
  • (\d{4}-\d{2}-\d{2})-捕获第1组:类似日期的模式
  • \s*-超过0个空格
  • :story_points:-文字:story_points:子字符串
  • \s*-超过0个空格
  • (\d+\.\d+)?-捕获组2(可选,由于?):1位以上的数字,.和1位以上的数字。

答案 2 :(得分:0)

r = /
    \A                  # match beginning of string
    :date:              # match string
    [ ]+                # match one or more spaces
    (\d{4}-\d{2}-\d{2}) # match string in capture group 1
    \n                  # match newline
    [ ]+                # match one or more spaces
    :story_points:      # match string
    [ ]+                # match one or more paces
    (                   # begin capture group 2
      \d+\.\d+          # match a non-negative float 
      |                 # or
      [ ]+              # match one or more spaces
    )                   # end capture group 2
    /x                  # free-spacing regex definition mode

arr.each_with_object([]) do |s,a|
  res = s.scan(r).flatten
  a << res unless res.empty?
end.transpose.tap { |a| a[1].map! { |s| s.to_f.to_s } }
  #=> [["2018-07-31", "2018-08-01", "2018-08-22"], ["4.0", "0.0", "8.0"]]

常规形式的正则表达式如下。

    r = /\A:date: +(\d{4}-\d{2}-\d{2})\n +:story_points: +(\d+\.\d+| +)/

使用自由间距模式时,字符类外部的空格将被删除,这就是为什么我用常规形式的正则表达式替换了[ ]的原因。 / +\n/可以用/\s+/代替,但允许使用制表符,其他空格字符,无空格和多个换行符。

请注意以下中间计算。

arr.each_with_object([]) do |s,a|
  res = s.scan(r).flatten
  a << res unless res.empty?
end
  #=> [["2018-07-31", "4.0"], ["2018-08-01", " "], ["2018-08-22", "8.0"]]

我用Object#tap代替了以下内容。

a = arr.each_with_object([]) do |s,a|
  res = s.scan(r).flatten
  a << res unless res.empty?
end.transpose
a[1].map! { |s| s.to_f.to_s }
a