变量魔法和从文件中读取

时间:2021-07-19 03:03:55

Assume, i got the following file (input.txt):

假设我有以下文件(input.txt):

name = "Peter"
age = 26
family_status = married

Mentioned lines can be stored in a random order, lie:

所述行可以按随机顺序存储,lie:

family_status = married
name = "Peter"
age = 26

In my program I also have variables family_status, age and name. How do I in a single cycle read those lines from file and assign correspond variables with the values?

在我的程序中,我也有变量family_status、age和name。在一个循环中,I如何从文件中读取这些行,并分配与值对应的变量?

3 个解决方案

#1


4  

Setting Variables

This depends on several facts.

这取决于几个事实。

  • What kind of variables do you have (local variables, instance variables, class variables, or global variables)
  • 有哪些变量(局部变量、实例变量、类变量或全局变量)
  • What kind of type is family_status (String, Symbol, whatever)
  • family_status(字符串、符号等)

I assume you are using instance variables for this:

我假设您使用的是实例变量:

def read_vars(io, vars)
  io.each do |line|
    # ensure the line has the right format (name = var)
    raise "wrong format" unless line=~ /^\s*(\w+)\s*=\s*"?(.*?)"?\s+$/
    var= :"@#{$1}"
    # pick the type of the data
    value= case vars[var]
    when String
      $2
    when Integer
      $2.to_i
    when Symbol
      $2.to_sym
    else
      raise "invalid var"
    end
    instance_variable_set(var, value)
  end
end

read_vars(File.read("input.txt", :@age => Integer, :@name => String, :@family_status => Symbol )

If you are not using instance variables you have to change the instacne_variable_set and var= :"@... line to you needs. This code has the following advantages:

如果您没有使用实例变量,则必须更改instacne_variable_set和var=:“@…”行你的需要。该代码具有以下优点:

  • You control which variables can be set
  • 您可以控制可以设置哪些变量
  • You control which types these variables have
  • 您可以控制这些变量的类型
  • You can easily add new variables and/or change types of variables without changing the read code
  • 您可以轻松地添加新的变量和/或更改变量类型,而无需更改读取代码
  • You can use this code to read entirely different files, without writing new code for it
  • 您可以使用此代码读取完全不同的文件,而无需为其编写新的代码

reading as YAML

If your needs are not as specific as in your question I would go an entirely different approach to this.

如果你的需求不像你的问题那样具体,我将采取完全不同的方法来解决这个问题。

I would write the input.txt as a yaml file. In yaml syntax it would look like this:

我把输入写出来。txt作为yaml文件。在yaml语法中是这样的:

---
name: Peter
age: 26
family_status: :married

You can read it with:

你可以这样读:

YAML.load(File.read("input.txt")) # => {"name" => "Peter", "age" => 26, "family_status" => :married }

Be carefull if you don't control the input.txt file, you don't control which types the data will have. I would name the file input.yaml instead of input.txt. If you want to know more, about how to write yaml files have a look at: http://yaml.kwiki.org/?YamlInFiveMinutes. More infos about yaml and ruby can be found at http://www.ruby-doc.org/stdlib/libdoc/yaml/rdoc/index.html.

如果你不控制输入,就要小心。txt文件,你不能控制数据的类型。我将命名文件输入。代替input.txt yaml。如果您想了解更多关于如何编写yaml文件的信息,请查看:http://yaml.kwiki.org/?关于yaml和ruby的更多信息可以在http://www.ruby-doc.org/stdlib/libdoc/yaml/rdoc/index.html中找到。

#2


2  

Assuming the file is really as regular as your example, you can slurp everything into a nice hash like this:

假设这个文件真的和你的例子一样常规,你可以把所有东西都拖进一个这样的散列:

input = IO.read("input.txt")
input_hash = Hash[*input.gsub(/"/,"").split(/\s*[\n=]\s*/)]

That gives you:

给你:

=> {"name"=>"Peter", "family_status"=>"married", "age"=>"26"}

But then you're really going to need some variable-specific code to do whatever type-handling you want, particularly for whatever family_status is...

但是,你真的需要一些特定的代码来完成你想要的任何类型的处理,特别是对于family_status…

#3


0  

You can try this. Not pretty on a single line though:

你可以试试这个。但在单行中就不太妙了:

class Test
  attr_accessor :name, :age, :family_status

  def load
    File.foreach('input.txt') do |line|
      match = line.match /^(\S+)\s*=\s*"?(\S+?)"?\s*$/
      self.send("#{match[1]}=", match[2]) if match
    end
  end
end

test = Test.new
test.load

#1


4  

Setting Variables

This depends on several facts.

这取决于几个事实。

  • What kind of variables do you have (local variables, instance variables, class variables, or global variables)
  • 有哪些变量(局部变量、实例变量、类变量或全局变量)
  • What kind of type is family_status (String, Symbol, whatever)
  • family_status(字符串、符号等)

I assume you are using instance variables for this:

我假设您使用的是实例变量:

def read_vars(io, vars)
  io.each do |line|
    # ensure the line has the right format (name = var)
    raise "wrong format" unless line=~ /^\s*(\w+)\s*=\s*"?(.*?)"?\s+$/
    var= :"@#{$1}"
    # pick the type of the data
    value= case vars[var]
    when String
      $2
    when Integer
      $2.to_i
    when Symbol
      $2.to_sym
    else
      raise "invalid var"
    end
    instance_variable_set(var, value)
  end
end

read_vars(File.read("input.txt", :@age => Integer, :@name => String, :@family_status => Symbol )

If you are not using instance variables you have to change the instacne_variable_set and var= :"@... line to you needs. This code has the following advantages:

如果您没有使用实例变量,则必须更改instacne_variable_set和var=:“@…”行你的需要。该代码具有以下优点:

  • You control which variables can be set
  • 您可以控制可以设置哪些变量
  • You control which types these variables have
  • 您可以控制这些变量的类型
  • You can easily add new variables and/or change types of variables without changing the read code
  • 您可以轻松地添加新的变量和/或更改变量类型,而无需更改读取代码
  • You can use this code to read entirely different files, without writing new code for it
  • 您可以使用此代码读取完全不同的文件,而无需为其编写新的代码

reading as YAML

If your needs are not as specific as in your question I would go an entirely different approach to this.

如果你的需求不像你的问题那样具体,我将采取完全不同的方法来解决这个问题。

I would write the input.txt as a yaml file. In yaml syntax it would look like this:

我把输入写出来。txt作为yaml文件。在yaml语法中是这样的:

---
name: Peter
age: 26
family_status: :married

You can read it with:

你可以这样读:

YAML.load(File.read("input.txt")) # => {"name" => "Peter", "age" => 26, "family_status" => :married }

Be carefull if you don't control the input.txt file, you don't control which types the data will have. I would name the file input.yaml instead of input.txt. If you want to know more, about how to write yaml files have a look at: http://yaml.kwiki.org/?YamlInFiveMinutes. More infos about yaml and ruby can be found at http://www.ruby-doc.org/stdlib/libdoc/yaml/rdoc/index.html.

如果你不控制输入,就要小心。txt文件,你不能控制数据的类型。我将命名文件输入。代替input.txt yaml。如果您想了解更多关于如何编写yaml文件的信息,请查看:http://yaml.kwiki.org/?关于yaml和ruby的更多信息可以在http://www.ruby-doc.org/stdlib/libdoc/yaml/rdoc/index.html中找到。

#2


2  

Assuming the file is really as regular as your example, you can slurp everything into a nice hash like this:

假设这个文件真的和你的例子一样常规,你可以把所有东西都拖进一个这样的散列:

input = IO.read("input.txt")
input_hash = Hash[*input.gsub(/"/,"").split(/\s*[\n=]\s*/)]

That gives you:

给你:

=> {"name"=>"Peter", "family_status"=>"married", "age"=>"26"}

But then you're really going to need some variable-specific code to do whatever type-handling you want, particularly for whatever family_status is...

但是,你真的需要一些特定的代码来完成你想要的任何类型的处理,特别是对于family_status…

#3


0  

You can try this. Not pretty on a single line though:

你可以试试这个。但在单行中就不太妙了:

class Test
  attr_accessor :name, :age, :family_status

  def load
    File.foreach('input.txt') do |line|
      match = line.match /^(\S+)\s*=\s*"?(\S+?)"?\s*$/
      self.send("#{match[1]}=", match[2]) if match
    end
  end
end

test = Test.new
test.load