2008-12-06 35 views
29

在Ruby中,您可以引用字符串中的变量,并在运行时对它们进行插值。在Ruby中,您可以对从文件读取的数据执行字符串插值吗?

例如,如果您声明变量foo等于"Ted",并且您声明字符串"Hello, #{foo}"它将插值到"Hello, Ted"

我一直无法弄清楚如何对从文件读取的数据执行神奇的"#{}"插值。

在伪代码,可能是这个样子:

interpolated_string = File.new('myfile.txt').read.interpolate 

但是,去年interpolate方法不存在。

回答

18

除了插值之外,还可以使用erbThis blog给该局使用的简单的例子,

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

+1

或者使用类似液体的东西会更安全。这与erb的概念没有恶意用户破坏应用程序的能力相同。 – 2010-05-06 03:02:03

+1

使用eval可能会带来巨大的安全风险,除非您信任文件内容,否则不推荐使用。 – thesmart 2014-02-10 22:32:45

20

那么,我第二斯特施在这种情况下使用erb的答案。但是你可以像这样使用eval。如果data.txt中有内容:

he #{foo} he 

然后,你可以加载和插值这样的:

str = File.read("data.txt") 
foo = 3 
result = eval("\"" + str + "\"") 

而且result将是:

"he 3 he" 
+0

和往常一样,小心您的评估 – rampion 2008-12-06 17:53:59

+0

rampion是正确的。这对每个具有这种特征的语言都很重要。 – stesch 2008-12-06 18:47:59

5

的2个最明显的答案已经被给,但如果他们不是出于某种原因,有格式运算符:

>> x = 1 
=> 1 
>> File.read('temp') % ["#{x}", 'saddle'] 
=> "The number of horses is 1, where each horse has a saddle\n" 

其中代替#{}魔力,你有旧的(但经过时间考验)%的魔法......

21

我想这可能是你在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." 
7

红宝石刻面提供了一种方法String#interpolate

插值。提供使用Ruby字符串 插值mechinism的外部使用 的方法。

try = "hello" 
str = "\#{try}!!!" 
String.interpolate{ str } #=> "hello!!!" 

注:为了块neccessary到 得到那么调用者的结合。

9

您可以使用IO将文件读入字符串。读(文件名),然后使用该结果作为格式字符串(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 

结果“红宝石fill_in_name .rb“在终端:

My name is Joe Schmoe and I am here to talk about file interpolation today. 
0

使用daniel-lucraft的答案作为我的b (因为他似乎是唯一回答问题的人),我决定以稳健的方式解决这个问题。下面你会找到这个解决方案的代码。

# 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异常抱怨输入包含所有可用的分隔符字符。

0

不妨将我自己的解决方案投入混合。

irb(main):001:0> str = '#{13*3} Music' 
=> "\#{13*3} Music" 
irb(main):002:0> str.gsub(/\#\{(.*?)\}/) { |match| eval($1) } 
=> "39 Music" 

弱点是你想评估的表达式可能有更多的{},所以正则表达式可能应该被改进。

相关问题