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