Насколько я понимаю, вы хотите извлечь слова, попадающие между строк '#BLOCK'
, со словами, разделенными строкой, каждый символ которой является символом в строке "^ {}()\"\n#"
.Альтернативное толкование, к которому я также обращусь, заключается в том, что должны быть извлечены только символы этих слов.
В заголовке вопроса требуется регулярное выражение (прилагательное "Rails" должно бытьударил, как бессмысленно).Я рекомендую не использовать единственное регулярное выражение для этой проблемы.Код, который я привел ниже, на мой взгляд, более прямой, его легче отслеживать и тестировать, и его легче поддерживать, если требования изменятся в будущем.
Код
def exclude(str)
arr = str.split(/^#BLOCK$/).drop(1)
arr.pop unless str.end_with?('#BLOCK')
arr.flat_map { |s| s.scan(/[^ {}()"\n]+/) }
end
Примеры
str =<<END
cat
#BLOCK
#NAME PC8
#TYPE GHD3
#PROGRAM "FooBar" 2.0
#DATE 20190501
#BASE 3740 "TXGH3789"
#BLOCK
#DATE 20000101
#BASE 0473 "9873HGXR"
#PROGRAM "BarBaz" 3.0
#BLOCK
dog
END
extract str
#=> ["#NAME", "PC8", "#TYPE", "GHD3", "#PROGRAM", "FooBar",
# "2.0", "#DATE", "20190501", "#BASE", "3740", "TXGH3789"]
Теперь сформируйте строку из str
, которая существует и заканчивается линиями'#BLOCK'
.
str1 = str.gsub(/^cat\n|^dog\n/, '')
puts str1
#BLOCK
#NAME PC8
#TYPE GHD3
#PROGRAM "FooBar" 2.0
#DATE 20190501
#BASE 3740 "TXGH3789"
#BLOCK
#DATE 20000101
#BASE 0473 "9873HGXR"
#PROGRAM "BarBaz" 3.0
#BLOCK
Мы видим, что
exclude(str1)
#=> ["#NAME", "PC8", "#TYPE", "GHD3", "#PROGRAM", "FooBar", "2.0",
# "#DATE", "20190501", "#BASE", "3740", "TXGH3789", "#DATE",
# "20000101", "#BASE", "0473", "9873HGXR", "#PROGRAM", "BarBaz", "3.0"]
возвращает тот же массив, что и exclude(str)
.
Объяснение
Для str
, как определено выше, следующие шаги:
arr = str.split(/^#BLOCK$/)
#=> ["cat\n",
# "\n#NAME PC8\n#TYPE GHD3\n...\"TXGH3789\"\n",
# "\n#DATE 20000101\n#BASE 0473...\"BarBaz\" 3.0\n",
# "\ndog\n"]
arr = arr.drop(1)
# ["\n#NAME PC8\n#TYPE GHD3\n...\"TXGH3789\"\n",
# "\n#DATE 20000101\n#BASE 0473...\"BarBaz\" 3.0\n",
# "\ndog\n"]
str.end_with?('#BLOCK')
#=> false
arr.pop
#=> "\ndog\n"
arr
#=> ["\n#NAME PC8\n#TYPE GHD3\n...\"TXGH3789\"\n",
# "\n#DATE 20000101\n#BASE 0473...\"BarBaz\" 3.0\n"]
arr.flat_map { |s| s.scan(/[^ {}()"\n]+/) }
#=> ["#NAME", "PC8", "#TYPE", "GHD3", "#PROGRAM", "FooBar", "2.0",
# "#DATE", "20190501", "#BASE", "3740", "TXGH3789", "#DATE",
# "20000101", "#BASE", "0473", "9873HGXR", "#PROGRAM", "BarBaz", "3.0"]
Альтернативная интерпретация вопроса
Если только символы словв extract(str)
желательно, можно написать:
extract(str).join
#=> "#NAMEPC8#TYPEGHD3#PROGRAMFooBar2.0#DATE20190501#BASE3740TXGH3789"
или
extract(str).join.chars
#=> ["#", "N", "A", "M", "E", "P",..., "z", "3", ".", "0"]
или удалить '+'
в регулярном выражении, которое является аргументом scan
:
def exclude(str)
arr = str.split(/^#BLOCK$/).drop(1)
arr.pop unless str.end_with?('#BLOCK')
arr.flat_map { |s| s.scan(/[^ {}()"\n]/) }
end
exclude(str)
#=> ["#", "N", "A", "M", "E", "P",..., "z", "3", ".", "0"]