Разделить строку с несколькими разделителями в Ruby

Возьмем, например, у меня строка вроде этого:

options = "Cake or pie, ice cream, or pudding"

Я хочу иметь возможность разделить строку с помощью or, , и , or.

Дело в том, что я смог это сделать, но только сначала проанализировав , и , or, а затем разделив каждый элемент массива на or, затем сглаживая результирующий массив следующим образом:

options = options.split(/(?:\s?or\s)*([^,]+)(?:,\s*)*/).reject(&:empty?);
options.each_index {|index| options[index] = options[index].sub("?","").split(" or "); }

Результирующий массив как таковой: ["Cake", "pie", "ice cream", "pudding"]

Есть ли более эффективный (или более простой) способ разделить мою строку на эти три разделителя?

Ответ 1

Как насчет следующего:

options.gsub(/ or /i, ",").split(",").map(&:strip).reject(&:empty?)
  • заменяет все разделители, но ,
  • разбивает его на ,
  • обрезает каждого символа, так как материал типа ice cream с ведущим пространством может быть оставлен
  • удаляет все пустые строки

Ответ 2

Прежде всего, ваш метод может быть немного упрощен с помощью Array#flatten:

>> options.split(',').map{|x|x.split 'or'}.flatten.map(&:strip).reject(&:empty?)
=> ["Cake", "pie", "ice cream", "pudding"]

Я бы предпочел использовать одно регулярное выражение:

>> options.split /\s*, or\s+|\s*,\s*|\s+or\s+/
=> ["Cake", "pie", "ice cream", "pudding"]

Вы можете использовать | в регулярном выражении, чтобы дать альтернативы, а put , or сначала гарантирует, что он не произведет пустой элемент. Захват пробела с регулярным выражением, вероятно, лучше всего подходит для эффективности, так как вам не нужно снова сканировать массив.

Как указывает Забба, вы все равно можете отклонить пустые элементы, предложив это решение:

>> options.split(/,|\sor\s/).map(&:strip).reject(&:empty?)
=> ["Cake", "pie", "ice cream", "pudding"]

Ответ 3

Как "or" и "," делает то же самое, лучший подход заключается в том, чтобы сообщить регулярному выражению, что несколько случаев следует рассматривать так же, как один случай:

options = "Cake or pie, ice cream, or pudding"
regex = /(?:\s*(?:,|or)\s*)+/
options.split(regex)