Rails регулярное выражение исключает символы конца пробелы между словом - PullRequest
2 голосов
/ 22 июня 2019

Я пытаюсь отметить каждую строку, находящуюся в двух #BLOCK строках.

Кроме того, я хочу исключить все символы [""," ",{},(),\n]

#BLOCK
#NAME {PC8}
#TYPE GHD3
#PROGRAM "FooBar" (2.0)
#DATE 20190501
#BASE 3740 "TXGH3789"
#BLOCK

Прямо сейчас,У меня есть два решения, но я хочу объединить их в одно.

Я использую Rubular и ссылки здесь:

Пример 1: https://rubular.com/r/bd2AxaHB2QLGpt

Пример 2:https://rubular.com/r/vmxm2kugNhnDCS

Я попробовал эти два решения:

  1. (?<=#BLOCK\n)(.*)(?=#BLOCK) Это работает, и это помечает все в двух #BLOCK строках.

  2. [^,{},(),""," ",\n] Это работает для исключения этих символов, но не помечает содержимое между двумя #BLOCK строками.

Как можно объединить обачтобы получить ожидаемый результат, как я описал в начале?

Ожидаемый результат - два пометить все между #BLOCK строками и исключить такие символы, как [{},(),""," ",\n].

Ответы [ 2 ]

3 голосов
/ 22 июня 2019

Если под "отметкой" вы подразумеваете Совпадение , вы можете попробовать это, я думаю.
Он использует конструкцию \G.

(Примечание. Ruby использует значение //m для обозначения Dot-all )

( update - не пропустить следующий блок без перезапуска)

/(?:(?:(?<=\#BLOCK\n)|(?!^)\G))[,{}()"\s]*\K(?!\#BLOCK\b)[^,{}()"\s](?=.*\#BLOCK\b)/m

https://rubular.com/r/TxlU9yhiUJkrok

Разъяснения
Примечание. Это регулярное выражение соответствует одному символу за раз.

 (?:
      (?<= \#BLOCK  \n )            # A block behind
   |                              # or,
      (?! ^ )                       # Not the BOS
      \G                            # Start matching where last match left off
 )
 [,{}()"\s]*                   # Consume optional punctuation and whitespace
 \K                            # Disregard anything matched so far
 (?! \#BLOCK \b )              # Don't go past next block
 [^,{}()"\s]                   # Get a single non-punct nor whitespace char
 (?= .* \#BLOCK \b )           # Only if there is a block ahead

Для сопоставления кусков символов используйте этот.

/(?:(?<=\#BLOCK\n)|(?!^)\G)[,{}()"\s]*\K(?=.+\#BLOCK\b)(?:(?!\#BLOCK\b)[^,{}()"\s])+/m

https://rubular.com/r/kyhqnOtIrmrnJ7

объяснил

 (?:
      (?<= \#BLOCK  \n )            # A block behind
   |                              # or,
      (?! ^ )                       # Not the BOS
      \G                            # Start matching where last match left off
 )
 [,{}()"\s]*                   # Consume optional punctuation and whitespace
 \K                            # Disregard anything matched so far
 (?= .+ \#BLOCK \b )           # Check that there is a block ahead
 (?:
      (?! \#BLOCK \b )              # Don't go past next block
      [^,{}()"\s]                   # Get a single non-punct nor whitespace char
 )+
2 голосов
/ 22 июня 2019

Насколько я понимаю, вы хотите извлечь слова, попадающие между строк '#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"] 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...