Возможно, это можно сделать одним шаблоном регулярных выражений, но я верю, что шаблоны должны быть простыми. Regex может быть коварным и скрывать множество мелких ошибок. Сделайте это простым, чтобы избежать этого, а затем настройте.
text = <<EOT
RAILS_ENV=production
listen_address = 127.0.0.1 # localhost only by default
PATH="/usr/local/bin"
EOT
text.scan(/^([^=]+)=(.+)/)
# => [["RAILS_ENV", "production"], ["listen_address ", " 127.0.0.1 # localhost only by default"], ["PATH", "\"/usr/local/bin\""]]
Обрезать завершающий комментарий легко в следующем map
:
text.scan(/^([^=]+)=(.+)/).map{ |n,v| [ n, v.sub(/#.+/, '') ] }
# => [["RAILS_ENV", "production"], ["listen_address ", " 127.0.0.1 "], ["PATH", "\"/usr/local/bin\""]]
Если вы хотите нормализовать все ваши имена / значения, чтобы в них не было лишних пробелов, вы можете сделать это также в map
:
text.scan(/^([^=]+)=(.+)/).map{ |n,v| [ n.strip, v.sub(/#.+/, '').strip ] }
=> [["RAILS_ENV", "production"], ["listen_address", "127.0.0.1"], ["PATH", "\"/usr/local/bin\""]]
Регулярное выражение "/^([^=]+)=(.+)/
" делает:
- «
^
» - это «В начале строки», то есть символ после «\ n». Это не то же самое, что начало строки, которое будет \A
. Есть важное различие, поэтому, если вы не понимаете, что такое два, будет хорошей идеей узнать, когда и почему вы хотите использовать одно поверх другого. Это одно из тех мест, где регулярные выражения могут быть коварными.
- «
([^=]+)
» - это «Захватить все, что не является знаком равенства».
- "
=
" - это, очевидно, знак равенства, который мы искали на предыдущем шаге.
- "
(.+)
" собирается захватить все после знака равенства.
Я специально держал вышеприведенный образец простым. Для производственного использования я бы немного ужесточил шаблоны, используя некоторые «жадные» флаги, а также завершающий якорь «$
»:
text.scan(/^([^=]+?)=(.+)$/).map{ |n,v| [ n.strip, v.sub(/#.+/, '').strip ] }
=> [["RAILS_ENV", "production"], ["listen_address", "127.0.0.1"], ["PATH", "\"/usr/local/bin\""]]
+?
означает найти первое совпадение '='. Это уже подразумевается при использовании [^=]
, но +?
делает это еще более очевидным, чем я хочу. Я могу обойтись без ?
, но это скорее самостоятельная документация для последующего обслуживания. В вашем случае он должен быть мягким, но его стоит хранить в своей сумке Regex Bag 'o Tricks.
$
означает конец строки, то есть место, непосредственно предшествующее EOL, концу строки AKA или возврату каретки. Это также подразумевается, но вставка в шаблон делает более очевидным то, что я ищу.
РЕДАКТИРОВАТЬ, чтобы отследить добавленный тест OP:
text = <<EOT
RAILS_ENV=production
listen_address = 127.0.0.1 # localhost only by default
PATH="/usr/local/bin"
HOSTNAME=`cat /etc/hostname`
EOT
text.scan( /^ ( [^=]+? ) = ( .+ ) $/x ).map{ |n,v| [ n.strip, v.sub(/#.+/, '').strip ] }
=> [["RAILS_ENV", "production"], ["listen_address", "127.0.0.1"], ["PATH", "\"/usr/local/bin\""], ["HOSTNAME", "`cat /etc/hostname`"]]
Если бы я писал это для себя, для удобства я бы сгенерировал хеш:
Hash[ text.scan( /^ ( [^=]+? ) = ( .+ ) $/x ).map{ |n,v| [ n.strip, v.sub(/#.+/, '').strip ] } ]
=> {"RAILS_ENV"=>"production", "listen_address"=>"127.0.0.1", "PATH"=>"\"/usr/local/bin\"", "HOSTNAME"=>"`cat /etc/hostname`"}