Ruby повторяющиеся значения соответствуют регулярному выражению, но умнее тогда заглянуть в будущее - PullRequest
2 голосов
/ 20 февраля 2020

у меня есть строка вроде:

(:a 100 :b (300 400 500 "hello") :c "hello")

В идеале мне нужно сопоставить группы, подобные этой:

": a", "100"

": b "," 300 400 500 \ "hello \" "

": c "" hello "

Итак, как вы видите, это простое сопоставление значения ключа из free-from-lisp- как код.

Я пробовал много шаблонов регулярных выражений, таких как: (:\w+)(.+)(?::\w+), но это не очень полезно для меня.

Полное описание шаблонов: https://rubular.com/r/khV8BWzJMtkbwv

Подходит ли регулярное выражение для такого анализа или мне просто написать свой простой парсер / использовать готовый?

1 Ответ

2 голосов
/ 20 февраля 2020
str = '(:a 100 :b (300 400 500 "hello") :c "hello")'

arr = str.scan(/(:\p{Ll}+)\s+([^(\s]+|\([^)]+\))/)
  #=> [[":a", "100"],
  #    [":b", "(300 400 500 \"hello\")"],
  #    [":c", "\"hello\")"]]

Это не совсем то, что нужно, так как скобки сохраняются в "(300 400 500 \"hello\")". Это может быть рассмотрено на отдельном шаге.

arr.map { |a,b| [a, b.gsub(/\A\(|\)\z/, '')] }
  #=> [[":a", "100"],
  #    [":b", "300 400 500 \"hello\""],
  #    [":c", "\"hello\""]]

Мы могли бы написать регулярное выражение в свободном интервале , чтобы сделать его самодокументированным:

/
(           # begin capture group 1 
  :         # match ':'
  \p{Ll}+   # match 1+ lower case Unicode letters
)           # end capture group 1
\s+         # match 1+ whitespaces
(           # begin capture group 2
  [^(\s]+   # match 1+ chars other than '(' and whitespace
  |         # or
  \(        # match a left paren
  [^)]+     # match 1+ chars other then ')'
  \)        # match ')'
)           # end capture group 2
/x          # free-spacing regex definition mode
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...