'gsub' 中的默认值
Default value in '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 "
]
我想在各自的数组中提取 date
和 story_points
的值。如果缺少 story_points
的值,则应提供 "0.0"
的默认值。输出应如下所示:
["2018-07-31", "2018-08-01", "2018-08-22"]
["4.0", "0.0", "8.0"]
我已经按照另一位用户在我之前 post 中的建议尝试了以下方法:
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"]
我无法获取默认值。有人可以帮忙吗?
试试下面的代码:
arr[1..-1].map { |s| (s.match(/(?<=:story_points: )\d{1}.\d{1}/) || '0.0').to_s }
#=> ["4.0", "0.0", "8.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" ]
图案解释
:date:
- 文字 :date:
子串
\s*
- 0+ 个空格
(\d{4}-\d{2}-\d{2})
- 捕获组 1:类似日期的模式
\s*
- 0+ 个空格
:story_points:
- 文字 :story_points:
子串
\s*
- 0+ 个空格
(\d+\.\d+)?
- 捕获组 2(可选,由于 ?
):1+ 位,.
和 1+ 位。
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
我有一个如下所示的数组:
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 "
]
我想在各自的数组中提取 date
和 story_points
的值。如果缺少 story_points
的值,则应提供 "0.0"
的默认值。输出应如下所示:
["2018-07-31", "2018-08-01", "2018-08-22"]
["4.0", "0.0", "8.0"]
我已经按照另一位用户在我之前 post 中的建议尝试了以下方法:
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"]
我无法获取默认值。有人可以帮忙吗?
试试下面的代码:
arr[1..-1].map { |s| (s.match(/(?<=:story_points: )\d{1}.\d{1}/) || '0.0').to_s }
#=> ["4.0", "0.0", "8.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" ]
图案解释
:date:
- 文字:date:
子串\s*
- 0+ 个空格(\d{4}-\d{2}-\d{2})
- 捕获组 1:类似日期的模式\s*
- 0+ 个空格:story_points:
- 文字:story_points:
子串\s*
- 0+ 个空格(\d+\.\d+)?
- 捕获组 2(可选,由于?
):1+ 位,.
和 1+ 位。
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