从文件中评估某些正则表达式以替换字符串中的字符



我是ruby新手,请原谅我的无知:(

我刚刚了解了eval,也读到了它的阴暗面。

到目前为止我读到的内容:

  • Ruby中的eval何时对正?

  • "eval"应该是讨厌的吗?

  • Ruby Eval与Ruby代码的执行

所以我要做的是读取一个文件,其中有一些文本,如/e/ 3,它将在评估后用3替换每个e

到目前为止我做了什么:(工作,但…(

def evaluate_lines
result="elt"
IO.foreach("test.txt") do |reg|
reg=reg.chomp.delete(' ')
puts reg
result=result.gsub(eval(reg[0..2]),"#{reg[3..reg.length]}" )
p result
end
end

test.txt文件的内容

/e/ 3
/l/ 1
/t/ 7
/$/ !
/$/ !!

这只是因为我知道文件中行的长度。

因此,假设我的文件具有以下/a-z/ 3,我的程序将无法执行预期的操作

备注

我尝试使用Regexp.new reg,结果得到了下面的//e/3/,在这种情况下没有太大帮助。

Regexp 的简单示例

str="/e/3"
result="elt"
result=result.gsub(Regexp.new str)
p result #outputs: #<Enumerator: "elt":gsub(//e/3/)>

我已经尝试过去掉斜线,但即使这样也不能提供所需的结果,因此gsub()需要两个参数,比如这个gsub(/e/, "3")

关于Regexp的用法,我已经阅读了将字符串转换为正则表达式ruby

虽然您可以编写一些东西来解析该文件,但由于必须解析正则表达式,它很快就会变得复杂。以//foo\/为例。

存在许多不完整的解决方案。您可以在空白处进行拆分,但在/foo bar/上会失败。

re, replace = line.split(/s+/, 2)

您可以使用正则表达式。这是第一针。

match = "/3/ 4".match(%r{^/(.*)/s+(.+)})

这在转义的/上失败了,我们需要更复杂的东西。

match = '/3// 4'.match(%r{A / ((?:[^/]|\/)*) / s+ (.+)}x)

我想这不是你的老师的意图,让你解析正则表达式。出于赋值的目的,在空白处进行拆分可能很好。你应该向你的老师澄清。


这是一种糟糕的数据格式。它是非标准的,很难解析,并且在替换方面有局限性。即使是制表符分隔的文件也会更好。

现在几乎没有理由使用非标准格式。最简单的方法是对文件使用标准的数据格式。YAML或JSON是最明显的选择。对于这样简单的数据,我建议使用JSON。

[
{ "re": "e", "replace": "3" },
{ "re": "l", "replace": "1" }
]

解析文件很简单,请使用内置的JSON库。

require 'json'
specs = JSON.load("test.json")

然后,您可以将它们用作哈希列表。

specs.each do |spec|
# No eval necessary.
re = Regexp.new(spec["re"])
# `gsub!` replaces in place
result.gsub!(re, spec["replace"])
end

数据文件是可扩展的。例如,如果以后要添加regex选项。

[
{ "re": "e", "replace": "3" },
{ "re": "l", "replace": "1", "options": ['IGNORECASE'] }
]

虽然老师可能指定了一个糟糕的格式,但作为一名开发人员,抵制糟糕的要求是一种很好的做法。

这里有一个非常简单的例子,它使用vi表示法,如s/.../.../s/.../.../g:

def rsub(text, spec)
_, mode, repl, with, flags = spec.match(%r[A(.)/((?:[^/]|\/)*)/((?:[^/]|\/)*)/(w*)z]).to_a
case (mode)
when 's'
if (flags.include?('g'))
text.gsub(Regexp.new(repl), with)
else
text.sub(Regexp.new(repl), with)
end
end
end

请注意,匹配器查找非斜杠字符([^/](一个字面斜杠组合(\/(,并相应地将这两部分分开。

在哪里你可以得到这样的结果:

rsub('sandwich', 's/and/or/')
# => "sorwich"
rsub('and/or', 's///,/')
# => "and,or"
rsub('stack overflow', 's/o/O/')
# => "stack Overflow"
rsub('stack overflow', 's/o/O/g')
# => "stack OverflOw"

这里的原理是,您可以使用一个非常简单的正则表达式来解析输入的正则表达式,并将清理后的数据馈送到Regexp.new中。这里绝对不需要eval,如果有什么严重限制你可以做的话。

只需做一点工作,您就可以更改正则表达式来解析现有文件中的内容,并使其执行您想要的操作。

最新更新