我有以下脚本
file = File.new("jobs.txt", 'r')
h = {}
jobs = []
salaries= []
while (line = file.gets)
if ( line =~ /CODE/)
cargos << line.gsub("\n", "")
elsif (line =~ /SALARY/)
salarios << line.gsub("\n", "")
end
end
h = Hash[jobs.zip(salaries)]
h.each { |code, salary| puts "#{code} ------ #{salary}" }
它完成了工作但是我想让正则表达式忽略/ CODE /它匹配并返回行的其余部分,是否可以在正则表达式上执行此操作或者我必须自己编写代码(替换字符串)或类似的东西)。
我主要想弄清楚如何使代码尽可能小。
答案 0 :(得分:3)
您的代码不是非常惯用的。这是未经测试的,但看起来是正确的:
salarios = []
cargos = []
File.foreach("jobs.txt") do |line|
if ( line =~ /CODE/)
cargos << line[/CODE - (\S+)/, 1]
elsif (line =~ /SALARY/)
salarios << line[/SALARY - (\S+)/, 1]
end
end
h = Hash[cargos.zip(salaries)]
h.each { |code, salary| puts "#{code} ------ #{salary}" }
line[/CODE = (\S+)/, 1]
利用String的[]
方法,它允许我们传递许多不同类型的参数。在这种情况下,我正在使用带有捕获的正则表达式模式。 1
告诉Ruby返回模式中的第一个捕获:
'CODE - XXXXX'[/CODE - (\S+)/, 1] # => "XXXXX"
\S+
表示“一个或多个非空格字符”,所以基本上模式是“查找'代码 - 然后捕获下一个字符串直到空格,制表符,换行符或回车符找到了。
查找和捕获值的另一种方法是在模式匹配并包含捕获时利用Ruby的“魔术”变量设置:
if ( line =~ /CODE - (\S+)/)
cargos << $1
elsif (line =~ /SALARY - (\S+)/)
salarios << $1
end
以下是一些证据:
'CODE - XXXXX' =~ /CODE - (\S+)/
$1 # => "XXXXX"
有些人不喜欢使用Regexp魔术变量;只要你立即使用它们,在其他任何东西都有机会运行另一个正则表达式匹配之前,你就可以了。如果发生另一场比赛,则可以覆盖变量并且您将遇到错误。
返回您的代码。使用带有块的foreach
来读取文件中的行,而不是打开并分配给变量。在块退出后,Ruby将自动关闭文件。
答案 1 :(得分:1)
如果输入类似于此CODE - XXXXX SALARY - XXXX OTHER INFO - XXXX
,则产生代码:
cargos << $1 if (line =~ /CODE\D+(\d+)/)
salarios << $1 if (line =~ /SALARY\D+(\d+)/)
此处正则表达式与CODE
匹配,后跟至少一个非数字(\D+
),后跟捕获的数字,这些数字代表代码
希望它有所帮助。
答案 2 :(得分:1)
分别搜索"CODE"
和"SALARY"
时需要注意。如果数据存在问题,您可能永远不会知道它(例如,"...CODE...CODE....SALARY..."
或可能引发异常(例如,zip
和{{1时执行jobs
是不同的大小)。
这是我怎么做的。如果数据正常,则该方法返回所需的结果,否则返回salaries
。
<强>代码强>
nil
<强>实施例强>
def doit(lines)
a = lines.select { |s| s =~ /CODE|SALARY/ }
return nil unless a.size.even?
jobs, salaries = a.each_slice(2).to_a.transpose
return nil unless jobs.all? { |l| l.scan(/CODE|SALARY/) == ["CODE"] }
return nil unless salaries.all? { |l| l.scan(/CODE|SALARY/) == ["SALARY"] }
jobs.zip salaries
end
<强>解释强>
text =<<-_
CODE and
SALARY are good, but
CODE without
any
SALARY is not
so good
_
doit(text.split("\n"))
#=> [["CODE and", "SALARY are good, but"], ["CODE without", "SALARY is not"]]
text =<<-_
CODE and
SALARY are good, but
SALARY without
CODE is even
better
_
doit(text.split("\n"))
#=> nil
text =<<-_
CODE and
SALARY are good, but
CODE is the main thing
_
doit(text.split("\n"))
#=> nil
会删除包含lines.select { |s| s =~ /CODE|SALARY/ }
或"CODE"
一词的所有行。"SELECT"
将所选行对,然后将枚举数转换为具有两列each_slice(2).to_a
提取数组的列。第一列应该是transpose
行;第二列,"CODE"
行。"SALARY"
确保每个jobs.all? { |l| l.scan(/CODE|SALARY/) == ["CODE"] }
行只包含"CODE"
一次,不包含"CODE"
。下一行代码与"SALARY"
行相反。