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