В Ruby вы можете выполнить интерполяцию строк при чтении данных из файла?
В Ruby вы можете ссылаться на переменные внутри строк, и они интерполируются во время выполнения.
Например, если вы объявляете переменную foo
equals "Ted"
и вы объявляете строку "Hello, #{foo}"
, она интерполируется на "Hello, Ted"
.
Мне не удалось выяснить, как выполнить магическую интерполяцию "#{}"
при чтении данных из файла.
В псевдокоде он может выглядеть примерно так:
interpolated_string = File.new('myfile.txt').read.interpolate
Но этот последний interpolate
метод не существует.
Ответы
Ответ 1
Вместо интерполяции вы можете использовать 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
.
Ответ 2
Я думаю, что это может быть самый простой и безопасный способ сделать то, что вы хотите в Ruby 1.9.x(sprintf не поддерживает ссылку по имени в 1.8.x): используйте функцию Kernel.sprintf для "reference by name". Пример:
>> 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."
Ответ 3
Ну, я второй ответ на вопрос об использовании erb в этой ситуации. Но вы можете использовать eval так. Если data.txt имеет содержимое:
he #{foo} he
Затем вы можете загрузить и интерполировать следующим образом:
str = File.read("data.txt")
foo = 3
result = eval("\"" + str + "\"")
И result
будет:
"he 3 he"
Ответ 4
Вы можете прочитать файл в строке с использованием 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.
Ответ 5
Ruby Facets предоставляет метод String # interpolate:
Интерполяция. Обеспечивает возможность экстенсивного использования механизма интерполяции строк Ruby.
try = "hello"
str = "\#{try}!!!"
String.interpolate{ str } #=> "hello!!!"
ПРИМЕЧАНИЕ. Блок необходим для того, чтобы затем получить привязку вызывающего.
Ответ 6
2 наиболее очевидных ответа уже были даны, но если они по какой-то причине не отвечают, есть оператор форматирования:
>> x = 1
=> 1
>> File.read('temp') % ["#{x}", 'saddle']
=> "The number of horses is 1, where each horse has a saddle\n"
где вместо магии # {} у вас есть старая (но проверенная временем) магия% s...
Ответ 7
Используя 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, жалуясь на то, что вход содержит все доступные символы разделителя.
Ответ 8
Можете также бросить свое решение в микс.
irb(main):001:0> str = '#{13*3} Music'
=> "\#{13*3} Music"
irb(main):002:0> str.gsub(/\#\{(.*?)\}/) { |match| eval($1) }
=> "39 Music"
Слабость заключается в том, что выражение, которое вы хотите оценить, может иметь в нем {}, поэтому регулярное выражение, вероятно, должно быть улучшено.