我问了原始问题here,并通过混合Ruby和正则表达式得到了实际的回答。现在,我的纯粹主义者想要知道:可以这可以在正则表达式中完成吗?我的直觉说它可以。有一个ABNF浮动为bash 2.0,虽然它不包括字符串转义。
规范
给定输入行是(1)来自bash风格脚本的变量(“key”)赋值,或者(2)来自典型配置文件(如postgresql.conf
)的键值设置,此正则表达式(或一对regexen)应该以这样的方式捕获键和值,以便我可以使用这些捕获来替换该键的新值。
您可以为shell风格和配置风格的行使用不同的正则表达式;呼叫者将知道使用哪个。
这里会有50分的赏金。我不能再加两天的赏金,所以在此之前我不会接受答案,但你可以立即开始回答。您可以获得积分:
示例:
给出输入
export RAILS_ENV=production
我应该能用Ruby编写:
match = THE_REGEX.match("export RAILS_ENV=production")
newline = "export #{match[:key]}=#{match[:value]}"
测试用例:shell样式
RAILS_ENV=development # Don't forget to change this for TechCrunch
HOSTNAME=`cat /etc/hostname`
plist=`cat "/Applications/Sublim\`e Text 2.app/Content's/Info.plist"`
# Optional bonus input: "#" present in the string
FORMAT=" ##0.00 passe\`" #comment
测试用例:配置样式
listen_addresses = 127.0.0.1 #localhost only by default
# listen_addresses = 0.0.0.0 commented out, should not match
出于这个挑战的目的,“正则表达式”和“正则表达式”意思相同,两者都可以引用您喜欢的任何常见风格,但我更喜欢Ruby 1.9兼容。
答案 0 :(得分:2)
我不确定完整的规格以及您在价值捕获组中的确切需求,但这应该适用于您的测试用例:
/
^\s*+
(?:export\s++)?
(?<key>\w++)
\s*+
=
\s*+
(?<value>
(?> "(?:[^"\\]+|\\.)*+"
| '(?:[^'\\]+|\\.)*+'
| `(?:[^`\\]+|\\.)*+`
| [^#\n\r]++
)
)
\s*+
(?:#.*+)?
$
/mx;
处理带有转义符的注释和引号。
Perl / PCRE的味道和引用。
Perl中的用法示例:
my $re = qr/
^\s*+
(?:export\s++)?
(?<key>\w++)
\s*+
=
\s*+
(?<value>
(?> "(?:[^"\\]+|\\.)*+"
| '(?:[^'\\]+|\\.)*+'
| `(?:[^`\\]+|\\.)*+`
| [^#\n\r]++
)
)
\s*+
(?:\#.*+)?
$
/mx;
my $str = <<'_TESTS_';
RAILS_ENV=development # Don't forget to change this for TechCrunch
HOSTNAME=`cat /etc/hostname`
plist=`cat "/Applications/Sublim\`e Text 2.app/Content's/Info.plist"`
# Optional bonus input: "#" present in the string
FORMAT=" ##0.00 passe\`" #comment
listen_addresses = 127.0.0.1 #localhost only by default
# listen_addresses = 0.0.0.0 commented out, should not match
TEST="foo'bar\"baz#"
TEST='foo\'bar"baz#\\'
_TESTS_
for(split /[\r\n]+/, $str){
print "line: $_\n";
print /$re/? "match: $1, $2\n": "no match\n";
print "\n";
}
输出:
line: RAILS_ENV=development # Don't forget to change this for TechCrunch
match: RAILS_ENV, development
line: HOSTNAME=`cat /etc/hostname`
match: HOSTNAME, `cat /etc/hostname`
line: plist=`cat "/Applications/Sublim\`e Text 2.app/Content's/Info.plist"`
match: plist, `cat "/Applications/Sublim\`e Text 2.app/Content's/Info.plist"`
line: # Optional bonus input: "#" present in the string
no match
line: FORMAT=" ##0.00 passe\`" #comment
match: FORMAT, " ##0.00 passe\`"
line: listen_addresses = 127.0.0.1 #localhost only by default
match: listen_addresses, 127.0.0.1
line: # listen_addresses = 0.0.0.0 commented out, should not match
no match
line: TEST="foo'bar\"baz#"
match: TEST, "foo'bar\"baz#"
line: TEST='foo\'bar"baz#\\'
match: TEST, 'foo\'bar"baz#\\'