En Ruby, ¿se puede realizar la interpolación de cadenas en los datos leídos desde un archivo?


En Ruby puede hacer referencia a variables dentro de cadenas y se interpolan en tiempo de ejecución.

Por ejemplo, si declaras una variable foo igual a "Ted" y declaras una cadena "Hello, #{foo}" interpola a "Hello, Ted".

No he sido capaz de averiguar cómo realizar la magia "#{}" interpolación en los datos leídos desde un archivo.

En pseudo código podría verse algo como esto:

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

Pero ese último método interpolate no existe.

Author: Andrew Grimm, 2008-12-06

8 answers

En lugar de interpolar, podría usar erb. Este blog da un ejemplo simple del uso de 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 podría ser utilizado, también. Pero la mayoría de las veces desea utilizar un sistema de plantillas simple como erb.

 19
Author: stesch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-10 19:26:59

Creo que esta podría ser la forma más fácil y segura de hacer lo que quieres en Ruby 1.9.x (sprintf no soporta referencia por nombre en 1.8.x): usar Kernel.característica sprintf de "referencia por nombre". Ejemplo:

>> 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." 
 25
Author: DavidG,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-31 19:55:48

Bueno, secundo la respuesta de stesch de usar erb en esta situación. Pero puedes usar eval así. If data.txt tiene contenido:

he #{foo} he

Entonces puedes cargar e interpolar así:

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

Y result será:

"he 3 he"
 21
Author: Daniel Lucraft,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-12-06 16:13:23

Puede leer el archivo en una cadena usando IO.leer (nombre de archivo), y luego utilizar el resultado como una cadena de formato (http://www.ruby-doc.org/core-2.0/String.html#method-i-25):

Miarchivo.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

Resultado de ejecutar "ruby fill_in_name.rb " en la terminal:

My name is Joe Schmoe and I am here to talk about file interpolation today.
 9
Author: Allan Tokuda,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-26 14:21:56

Ruby Facets proporciona una cadena # interpolate método:

Interpolar. Proporciona un medio de extenally usando la cadena de Ruby mecinismo de interpolación.

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

NOTA: El bloque necesario para obtener a continuación, la vinculación de la persona que llama.

 8
Author: Andrew Grimm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-11 20:24:33

Las 2 respuestas más obvias ya se han dado, pero si no lo hacen por alguna razón, está el operador de formato:

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

Donde en lugar de la magia #{} tienes la magia más antigua (pero probada en el tiempo) %s...

 6
Author: Purfideas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-25 13:33:23

Usando la respuesta de daniel-lucraft como mi base (ya que parece ser el único que respondió a la pregunta) decidí resolver este problema de una manera robusta. A continuación encontrará el código para esta solución.

# 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

Para la entrada

he #{foo} he

Se obtiene la salida

 "he 3 he"

La entrada

"he #{bad} he\n"

Generará una excepción NameError. Y la entrada

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

Levantará y Argumententerror excepción quejándose de que la entrada contiene todos los disponibles caracteres delimitadores.

 0
Author: G. Allen Morris III,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:17:29

También podría lanzar mi propia solución en la mezcla.

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

La debilidad es que la expresión que desea evaluar puede tener más { } en ella, por lo que la expresión regular probablemente debería mejorarse.

 0
Author: Trejkaz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-27 05:23:52