Захват необязательных данных, которым предшествует запятая - PullRequest
0 голосов
/ 29 апреля 2019

У меня есть несколько текстовых строк, с которыми я хотел бы сопоставить, при желании можно получить информацию о «результате», если она присутствует:

0-0: Called Strike
0-1: Foul ball, location: 2F
0-2: Double, (Line Drive, 3D)
0-0: Foul Ball, location: 2F
0-1: Ball
1-1: Double, (Line Drive, 9LD)
0-0: Called Strike
0-1: Ball
1-1: Foul Ball, location: 2F
1-2: Ball
2-2: Ball
3-2: Ground out, 3-1 (Groundball, 34)

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

^(?<balls>[0-3])-(?<strikes>[0-2]): (?<event>.*?(?=,|$))(?<outcome>.*$)

Что хорошо работает довольно , но когда дело доходит до компонента outcome матча, он включаетвсе пробелы в данных, поэтому для такой строки, как:

0-1: Foul ball, location: 2F, outcome соответствует , location: 2F.

Любое уточнение группы совпадений outcome приводит к несовпадению всех строк, в которых нет лишних данных, разделенных запятой.

Может кто-нибудь помочь мне закончитьВыражение regex, чтобы оно захватывало все после , и SPC как outcome, в то же время сопоставляя столбцы, у которых нет ,?

Ответы [ 4 ]

1 голос
/ 30 апреля 2019

У вас есть в списке несколько событий, которые могут произойти в игре в бейсбол: называется удар, мяч, удвоение и вылет.Это, конечно, только верхушка айсберга: вылет, фол, одиночный, тройной, домашний бег, жертва, ошибка, украденное основание, выброшенная попытка кражи, двойная игра, тройная игра и другие.Чтобы информация о событии была полезной, каждый тип события должен рассматриваться отдельно.Попытка сделать это с помощью одного регулярного выражения, по моему мнению, глупо.Ниже представлен подход, который можно рассмотреть.Оператор case должен быть значительно расширен, чтобы включать, помимо прочего, события, о которых я упоминал выше.

Код

def parse_events(arr)
  arr.map do |s|
    event = s[/\p{Lu}[\p{L} ]*(?=\,|\z)/].strip.downcase
    { event: event, count: s[0,3] }.merge(
    case event
    when "called strike", "ball"
      {} 
    when "foul ball"
      { location: s[/\d\p{L}+\z/] }
    when "double"  
      { type:     s[/(?<=\()[\p{L} ]+/].downcase,
        location: s[/\d\p{L}+(?=\)\z)/] }
    when "ground out"
      { sequence: s[/(?<=, )\d\-\d/],
        type:     s[/(?<=\()[\p{L} ]+/],
        location: s[/\d+(?=\)\z)/] }
    else  
      # raise exception
    end)
 end
end

Пример

arr = <<-END.split("\n").map(&:strip)
0-0: Called Strike
0-1: Foul ball, location: 2F
0-2: Double, (Line Drive, 3D)
0-0: Foul Ball, location: 2F
0-1: Ball
1-1: Double, (Line Drive, 9LD)
0-0: Called Strike
0-1: Ball
1-1: Foul Ball, location: 2F
1-2: Ball
2-2: Ball
3-2: Ground out, 3-1 (Groundball, 34)
END
  #=> ["0-0: Called Strike",
  #    "0-1: Foul ball, location: 2F",
  #    "0-2: Double, (Line Drive, 3D)",
  #    "0-0: Foul Ball, location: 2F",
  #    "0-1: Ball",
  #    "1-1: Double, (Line Drive, 9LD)",
  #    "0-0: Called Strike",
  #    "0-1: Ball",
  #    "1-1: Foul Ball, location: 2F",
  #    "1-2: Ball",
  #    "2-2: Ball",
  #    "3-2: Ground out, 3-1 (Groundball, 34)"]

parse_events arr
  #=> [{:event=>"called strike", :count=>"0-0"},
  #    {:event=>"foul ball", :count=>"0-1", :location=>"2F"},
  #    {:event=>"double", :count=>"0-2", :type=>"line drive", :location=>"3D"},
  #    {:event=>"foul ball", :count=>"0-0", :location=>"2F"},
  #    {:event=>"ball", :count=>"0-1"},
  #    {:event=>"double", :count=>"1-1", :type=>"line drive", :location=>"9LD"},
  #    {:event=>"called strike", :count=>"0-0"},
  #    {:event=>"ball", :count=>"0-1"},
  #    {:event=>"foul ball", :count=>"1-1", :location=>"2F"},
  #    {:event=>"ball", :count=>"1-2"},
  #    {:event=>"ball", :count=>"2-2"},
  #    {:event=>"ground out", :count=>"3-2", :sequence=>"3-1",
  #     :type=>"Groundball", :location=>"34"}] 
1 голос
/ 29 апреля 2019

Вы могли бы действительно сделать последнюю часть необязательной, используя необязательную группу без захвата (?:,\h*(?<outcome>.*$))? и сопоставляя запятую с 0+ раз горизонтальным пробельным символом, используя \h*.

Но вы также можете обновитьэта часть .*?(?=,|$) для использования отрицательного класса символов [^,\n\r]* для предотвращения ненужного возврата.

Ваше выражение может выглядеть так:

^(?<balls>[0-3])-(?<strikes>[0-2]): (?<event>[^,\n]*)(?:,\h*(?<outcome>.*$))?
                                             ^^^^^^^ 

См. Rubular demo

Вместо использования ^ и $ вы также можете выбрать использование \A и \Z якорей для подтверждения начала и концастрока.

1 голос
/ 29 апреля 2019

Попробуйте Regex: ^(?<balls>[0-3])-(?<strikes>[0-2]): (?<event>.*?(?=,|$))(?:, *(?<outcome>.*$))?

Демо

0 голосов
/ 29 апреля 2019

Назовите меня по-старому, но это не кричит мне. Кажется, что без этого было бы намного проще, если я не знаю ваших реальных характеристик.

def get_stuff(str)
  score, details = str.split(':')
  balls, strikes = score.split('-')
  event, *outcome = details.split(',')
  return [balls, strikes, event.strip, outcome.join(' ').strip]
end

input = File.read('input.txt')
input.lines.each do |line|
  p get_stuff(line)
end

Выходы

["0", "0", "Called Strike", ""]
["0", "1", "Foul ball", "location"]
["0", "2", "Double", "(Line Drive  3D)"]
["0", "0", "Foul Ball", "location"]
["0", "1", "Ball", ""]
["1", "1", "Double", "(Line Drive  9LD)"]
["0", "0", "Called Strike", ""]
["0", "1", "Ball", ""]
["1", "1", "Foul Ball", "location"]
["1", "2", "Ball", ""]
["2", "2", "Ball", ""]
["3", "2", "Ground out", "3-1 (Groundball  34)"]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...