使用 ARGV[] 参数向量在 Ruby 中传递正则表达式

Use ARGV[] argument vector to pass a regular expression in Ruby

我正在尝试在通过终端传递给 ARGV[] 的正则表达式上使用 gsubsub

终端查询:$ruby script.rb input.json "\[\{\"src\"\:\"

输入文件前两行:

[{
    "src":"http://something.com",
    "label":"FOO.jpg","name":"FOO",
    "srcName":"FOO.jpg"
}]
[{
    "src":"http://something123.com",
    "label":"FOO123.jpg",
    "name":"FOO123",
    "srcName":"FOO123.jpg"
}]

script.rb:

dir = File.dirname(ARGV[0])
output = File.new(dir + "/output_" + Time.now.strftime("%H_%M_%S") + ".json", "w")
open(ARGV[0]).each do |x|
x = x.sub(ARGV[1]),'')
output.puts(x) if !x.nil?
end
output.close

这确实是非常基础的东西,但我不太确定如何做到这一点。我试过了:

基于this answer in the thread Convert a string to regular expression ruby,你应该使用

x = x.sub(/#{ARGV[1]}/,'')

我用这个文件测试过它 (test.rb):

puts "You should not see any number [0123456789].".gsub(/#{ARGV[0]}/,'')

我这样调用文件:

ruby test.rb "\d+"
# => You should not see any number [].

对此进行冥想:

我写了一个小脚本包含:

puts ARGV[0].class 
puts ARGV[1].class

并将其保存到磁盘,然后 运行 使用:

ruby ~/Desktop/tests/test.rb foo /abc/

return编辑:

String
String

文档说:

The pattern is typically a Regexp; if given as a String, any regular expression metacharacters it contains will be interpreted literally, e.g. '\d' will match a backlash followed by ‘d’, instead of a digit.

这意味着正则表达式,虽然看起来是一个正则表达式,但它不是,它是一个字符串,因为ARGV只能return 字符串,因为命令行只能包含字符串。

当我们将字符串传递给 sub 时,Ruby 识别出它不是正则表达式,因此将其视为文字字符串。这是操作上的差异:

'foo'.sub('/o/', '') # => "foo"
'foo'.sub(/o/, '') # => "fo"

第一个在 "foo" 中找不到 "/o/",所以没有任何变化。它可以找到 /o/ 和 returns 替换两个 "o" 后的结果。

另一种看待它的方式是:

'foo'.match('/o/') # => nil
'foo'.match(/o/) # => #<MatchData "o">

其中 match 找不到任何字符串,但可以找到 /o/.

的匹配项

所有这些都会导致您的代码中发生的事情。因为 sub 被传递一个字符串,它试图对正则表达式进行文字匹配,但无法找到它。您需要将代码更改为:

sub(Regexp.new(ARGV[1]), '')

但这并不是必须改变的全部。 Regexp.new(...) 会将传入的内容转换为正则表达式,但如果您传入 '/o/',则生成的正则表达式将为:

Regexp.new('/o/') # => /\/o\//

这可能不是你想要的:

'foo'.match(/\/o\//) # => nil

相反你想要:

Regexp.new('o') # => /o/
'foo'.match(/o/) # => #<MatchData "o">

因此,除了更改代码外,您还需要确保传入的内容是有效的表达式,减去 任何前导和尾随 /