Значение по умолчанию в «gsub» - PullRequest
0 голосов
/ 01 октября 2018

У меня есть массив, который выглядит следующим образом:

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"]

Я попробовал следующее, как было предложено в моем предыдущем посте другим пользователем:

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 голосов
/ 01 октября 2018

Альтернативное решение на основе регулярных выражений, основанное на одном проходе по массиву:

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

Вот демонстрационная версия Rubular

Объяснение шаблона

  • :date: - буквальная :date: подстрока
  • \s* - 0+ пробелов
  • (\d{4}-\d{2}-\d{2}) - Группа захвата 1: шаблон типа даты
  • \s* - 0+ пробелов
  • :story_points: - буквальная :story_points: подстрока
  • \s* - 0+ пробелов
  • (\d+\.\d+)? - Группа захвата 2 (необязательно, из-за ?): 1+ цифр, . и 1+ цифр.
0 голосов
/ 01 октября 2018
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
0 голосов
/ 01 октября 2018

Попробуйте следующий код:

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