在 Ruby 中,可以对从文件读取的数据执行字符串插值吗?

发布于 2024-07-09 06:38:21 字数 394 浏览 6 评论 0原文

在 Ruby 中,您可以引用字符串内的变量,并且它们在运行时进行插值。

例如,如果您声明一个变量 foo 等于 "Ted" 并声明一个字符串 "Hello, #{foo}" 它会插入到 <代码>“你好,特德”。

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

在伪代码中,它可能看起来像这样:

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

但是最后一个 interpolate 方法不存在。

In Ruby you can reference variables inside strings and they are interpolated at runtime.

For example if you declare a variable foo equals "Ted" and you declare a string "Hello, #{foo}" it interpolates to "Hello, Ted".

I've not been able to figure out how to perform the magic "#{}" interpolation on data read from a file.

In pseudo code it might look something like this:

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

But that last interpolate method doesn't exist.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

ゞ记忆︶ㄣ 2024-07-16 06:38:22

您可以使用 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.

You can read the file into a string using IO.read(filename), and then use the result as a format string (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

result of running "ruby fill_in_name.rb" at the terminal:

My name is Joe Schmoe and I am here to talk about file interpolation today.
酒解孤独 2024-07-16 06:38:22

已经给出了 2 个最明显的答案,但如果由于某种原因没有给出答案,则有格式运算符:

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

您拥有较旧的(但经过时间考验的) %s 魔法,而不是 #{} 魔法 .. 。

The 2 most obvious answers have already been given, but if they don't to it for some reason, there's the format operator:

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

where instead of the #{} magic you have the older (but time-tested) %s magic ...

来世叙缘 2024-07-16 06:38:22

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

Using daniel-lucraft's answer as my base (as he seems to be the only one that answered the question) I decided to solve this problem in a robust manner. Below you will find the code for this solution.

# 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

for the input

he #{foo} he

you get the output

 "he 3 he"

The input

"he #{bad} he\n"

will raise a NameError exception. And the input

"\"'\u0002\u0003\u007F|+-"

will raise and ArgumentError exception complaining that the input contained all available delimiter characters.

耳根太软 2024-07-16 06:38:22

不妨将我自己的解决方案加入其中。

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

缺点是您要计算的表达式可能还包含 { } ,因此正则表达式可能需要改进。

Might as well throw my own solution into the mix.

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

The weakness is that the expression you want to evaluate may have further { } in it, so the regex should probably be improved.

爱的故事 2024-07-16 06:38:22

@andrewgrimm 的答案是正确的,但不完整。 Facets gem 具有 String 扩展,包括 interpolate,这正是原始问题所要求的。

$ gem install facets

几乎完全按照OP的要求使用它。 请注意 require 语句。

require 'facets/string/interpolate'

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

这是一个完整的工作示例:

require 'facets/string/interpolate'

string = 'There are #{thing1}s and #{thing2}s here.'
thing1 = 'stick'
thing2 = 'stone'

puts String.interpolate { string }

显示:

There are sticks and stones here.

The answer by @andrewgrimm was on the right track, but incomplete. The Facets gem has String extensions, including interpolate, which is precisely what the original question asked for.

$ gem install facets

Use it almost exactly as the OP requested. Note the require statement.

require 'facets/string/interpolate'

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

Here is a complete working example:

require 'facets/string/interpolate'

string = 'There are #{thing1}s and #{thing2}s here.'
thing1 = 'stick'
thing2 = 'stone'

puts String.interpolate { string }

Displays:

There are sticks and stones here.
东风软 2024-07-16 06:38: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." 

I think this might be the easiest and safest way to do what you want in Ruby 1.9.x (sprintf doesn't support reference by name in 1.8.x): use Kernel.sprintf feature of "reference by name". Example:

>> 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." 
A君 2024-07-16 06:38:21

好吧,我同意 stesch 在这种情况下使用 erb 的回答。 但你可以像这样使用 eval 。 如果 data.txt 包含内容:

he #{foo} he

那么您可以像这样加载和插值:

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

并且 结果 将是:

"he 3 he"

Well, I second stesch's answer of using erb in this situation. But you can use eval like this. If data.txt has contents:

he #{foo} he

Then you can load and interpolate like this:

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

And result will be:

"he 3 he"
零度° 2024-07-16 06:38:21

您可以使用 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

Instead of interpolating, you could use erb. This blog gives simple example of ERB usage,

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 could be used, too. But most of the time you want to use a simple template system like erb.

我只土不豪 2024-07-16 06:38:21

Ruby Facets 提供了 String#interpolate 方法:

插值。 提供了一种手段
外部使用 Ruby 字符串
插值机制。

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

注意:该块是必需的
然后获取调用者的绑定。

Ruby Facets provides a String#interpolate method:

Interpolate. Provides a means of
extenally using Ruby string
interpolation mechinism.

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

NOTE: The block neccessary in order to
get then binding of the caller.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文