在 Ruby 中,可以对从文件读取的数据执行字符串插值吗?
-
19-08-2019 - |
题
在 Ruby 中,您可以引用字符串内的变量,并且它们在运行时进行插值。
例如,如果您声明一个变量 foo
等于 "Ted"
然后你声明一个字符串 "Hello, #{foo}"
它插值到 "Hello, Ted"
.
我一直不知道如何施展魔法 "#{}"
对从文件读取的数据进行插值。
在伪代码中,它可能看起来像这样:
interpolated_string = File.new('myfile.txt').read.interpolate
但最后那个 interpolate
方法不存在。
解决方案
除了插的,你可以使用 erb
。 此博客给出ERB使用的简单的例子,
require 'erb'
name = "Rasmus"
template_string = "My name is <%= name %>"
template = ERB.new template_string
puts template.result # prints "My name is Rasmus"
Kernel#eval
可能是使用过。但大多数时候,你想用一个简单的模板系统,如erb
。
其他提示
我觉得这可能是你想用Ruby 1.9.x的是什么(sprintf的不支持1.8.x的名字引用)的最简单,最安全的方法:使用Kernel.sprintf功能“参考的名字”。例如:
>> mystring = "There are %{thing1}s and %{thing2}s here."
=> "There are %{thing1}s and %{thing2}s here."
>> vars = {:thing1 => "trees", :thing2 => "houses"}
=> {:thing1=>"trees", :thing2=>"houses"}
>> mystring % vars
=> "There are trees and houses here."
那么,在这种情况下使用ERB的我第二stesch的答案。但是你可以使用eval这样。如果data.txt中具有内容:
he #{foo} he
然后,可以加载和内插像这样:
str = File.read("data.txt")
foo = 3
result = eval("\"" + str + "\"")
和result
将是:
"he 3 he"
您可以使用 IO.read(filename) 将文件读入字符串,然后将结果用作格式字符串 (http://www.ruby-doc.org/core-2.0/String.html#method-i-25):
我的文件.txt:
My name is %{firstname} %{lastname} and I am here to talk about %{subject} today.
填写名称.rb:
sentence = IO.read('myfile.txt') % {
:firstname => 'Joe',
:lastname => 'Schmoe',
:subject => 'file interpolation'
}
puts sentence
在终端运行“ruby fill_in_name.rb”的结果:
My name is Joe Schmoe and I am here to talk about file interpolation today.
Ruby Facets 提供了 字符串#插值 方法:
插。提供了一种使用Ruby String插值机制的方法。
try = "hello"
str = "\#{try}!!!"
String.interpolate{ str } #=> "hello!!!"
笔记:为了获得呼叫者的绑定,块中心障碍。
在2个最明显的答案已经给出,但如果他们不给它的某些原因,还有的格式运算符:
>> x = 1
=> 1
>> File.read('temp') % ["#{x}", 'saddle']
=> "The number of horses is 1, where each horse has a saddle\n"
其中的#{}魔力,你有旧的(但经过时间考验)%的魔法,而不是...
使用丹尼尔 - lucraft 的答案,因为我的基地(他似乎是回答只有一个这个问题),我决定以稳健的方式来解决这个问题。下面你会发现这个解决方案的代码。
# encoding: utf-8
class String
INTERPOLATE_DELIMETER_LIST = [ '"', "'", "\x02", "\x03", "\x7F", '|', '+', '-' ]
def interpolate(data = {})
binding = Kernel.binding
data.each do |k, v|
binding.local_variable_set(k, v)
end
delemeter = nil
INTERPOLATE_DELIMETER_LIST.each do |k|
next if self.include? k
delemeter = k
break
end
raise ArgumentError, "String contains all the reserved characters" unless delemeter
e = s = delemeter
string = "%Q#{s}" + self + "#{e}"
binding.eval string
end
end
output =
begin
File.read("data.txt").interpolate(foo: 3)
rescue NameError => error
puts error
rescue ArgumentError => error
puts error
end
p output
对于输入
he #{foo} he
你得到的输出
"he 3 he"
输入
"he #{bad} he\n"
将引发NameError异常。和输入
"\"'\u0002\u0003\u007F|+-"
将提高和ArgumentError异常抱怨输入包含所有可用的分隔符。
不妨把我自己的溶液到混合物中。
irb(main):001:0> str = '#{13*3} Music'
=> "\#{13*3} Music"
irb(main):002:0> str.gsub(/\#\{(.*?)\}/) { |match| eval($1) }
=> "39 Music"
的缺点是,表达要评估可以进一步{}在它具有,所以正则表达式可能应该加以改进。