Regex захватывать необязательные группы в любом порядке - PullRequest
0 голосов
/ 26 февраля 2020

Я хотел бы захватывать группы на основе последовательного появления совпадающих групп в любом порядке. И когда один тип набора повторяется без альтернативного типа набора, альтернативный набор возвращается как ноль.

Таким образом, следующее:

"123 dog cat cow 456 678 890 sheep"

Возвращает следующее:

[["123", "dog"], [nil, "cat"], ["456", "cow"], ["678", nil], ["890", sheep]]

1 Ответ

1 голос
/ 26 февраля 2020

Регулярное выражение может дать нам часть пути, но я не верю полностью.

r = /
    (?:        # begin non-capture group
      \d+      # match 1+ digits
      [ ]      # match 1 space
      [^ \d]+  # match 1+ chars other than digits and spaces
      |        # or
      [^ \d]+  # match 1+ chars other than digits and spaces
      [ ]      # match 1 space
      \d+      # match 1+ digits
      |        # or
      [^ ]+    # match 1+ chars other than spaces
    )          # end non-capture group
    /x         # free-spacing regex definition mode               

str = "123 dog cat cow 456 678 890 sheep"

str.scan(r).map do |s|
  case s
  when /\d [^ \d]/
    s.split(' ')
  when /[^ \d] \d/
    s.split(' ').reverse
  when /\d/
    [s,nil]
  else
    [nil,s]
  end
end
  #=> [["123", "dog"], [nil, "cat"], ["456", "cow"],
  #    ["678", nil], ["890", "sheep"]] 

Примечание:

str.scan r
  #=> ["123 dog", "cat", "cow 456", "678", "890 sheep"]

Это регулярное выражение условно записано

/(?:\d+ [^ \d]+|[^ \d]+ \d+|[^ ]+)/

Вот еще одно решение, в котором используются только регулярные выражения

def doit(str)
  str.gsub(/[^ ]+/).with_object([]) do |s,a|
    prev = a.empty? ? [0,'a'] : a.last
    case s
    when /\A\d+\z/ # all digits
      if prev[0].nil?
        a[-1][0] = s
      else
        a << [s,nil]
      end
    when /\A\D+\z/ # all non-digits
      if prev[1].nil?
        a[-1][1] = s
      else
        a << [nil,s]
      end
    else
      raise ArgumentError
    end
  end
end

doit str
  #=> [["123", "dog"], [nil, "cat"], ["456", "cow"], ["678", nil],
  #    ["890", "sheep"]] 

Используется форма String # gsub , которая не имеет блока и поэтому возвращает перечислитель :

enum = str.gsub(/[^ ]+/)
  #=> #<Enumerator: "123 dog cat cow 456 678 890 sheep":gsub(/[^ ]+/)> 
enum.next
  #=> "123" 
enum.next
  #=> "dog"
...
enum.next
  #=> "sheep" 
enum.next
  #=> StopIteration (iteration reached an end)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...