在Ruby中,您可以引用字符串中的变量,并在运行时进行插值。
例如,如果您声明变量foo
等于"Ted"
并声明字符串"Hello, #{foo}"
,则会将其插入"Hello, Ted"
。
我无法弄清楚如何对从文件读取的数据执行魔术"#{}"
插值。
在伪代码中,它可能看起来像这样:
interpolated_string = File.new('myfile.txt').read.interpolate
但最后interpolate
方法不存在。
答案 0 :(得分:28)
我认为这可能是在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."
答案 1 :(得分:22)
嗯,我在这种情况下第二次使用erb的答案。但你可以像这样使用eval。如果data.txt包含内容:
he #{foo} he
然后你可以像这样加载和插值:
str = File.read("data.txt")
foo = 3
result = eval("\"" + str + "\"")
result
将是:
"he 3 he"
答案 2 :(得分:19)
您可以使用erb
而不是插值。 This blog给出了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
这样的简单模板系统。
答案 3 :(得分:9)
您可以使用IO.read(filename)将文件读入字符串,然后将结果用作格式字符串(http://www.ruby-doc.org/core-2.0/String.html#method-i-25):
myfile.txt的:
My name is %{firstname} %{lastname} and I am here to talk about %{subject} today.
fill_in_name.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.
答案 4 :(得分:8)
Ruby Facets提供了String#interpolate方法:
内插。提供一种手段 extenally使用Ruby字符串 插值机制。
try = "hello"
str = "\#{try}!!!"
String.interpolate{ str } #=> "hello!!!"
注意:块需要以便 然后绑定调用者。
答案 5 :(得分:6)
已经给出了两个最明显的答案,但是如果由于某些原因他们不这样做,那就是格式化运算符:
>> x = 1
=> 1
>> File.read('temp') % ["#{x}", 'saddle']
=> "The number of horses is 1, where each horse has a saddle\n"
而不是#{}魔法,你有较旧的(但经过时间考验的)%s魔法......
答案 6 :(得分:1)
使用daniel-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异常,抱怨输入包含所有可用的分隔符。
答案 7 :(得分:1)
不妨将我自己的解决方案投入到混音中。
irb(main):001:0> str = '#{13*3} Music'
=> "\#{13*3} Music"
irb(main):002:0> str.gsub(/\#\{(.*?)\}/) { |match| eval($1) }
=> "39 Music"
缺点是您要评估的表达式可能还有{},因此正则表达式可能会得到改进。