2009-10-16 3 views
2

Предположим, я получил следующий файл (input.txt):Переменные магии и чтение из файла

name = "Peter" 
age = 26 
family_status = married 

Указанные линии могут быть сохранены в случайном порядке, лежат:

family_status = married 
name = "Peter" 
age = 26 

В моей программе у меня также есть переменные family_status, возраст и имя. Как я в один цикл читаю эти строки из файла и присваиваю соответствующие переменные значениями?

ответ

4

Настройка переменных

Это зависит от нескольких фактов.

  • Какие переменные у вас есть (локальные переменные, переменные экземпляра, переменные класса, или глобальные переменные)
  • Какой тип является family_status (String,Symbol, независимо)

Я полагаю, вы используете переменные экземпляра для этого:

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) 

Если вы не используете переменные экземпляра, вы должны изменить instacne_variable_set и var= :"@... линия к вам. Этот код имеет следующие преимущества:

  • Вы контролируете, какие переменные могут быть установлены
  • управлять тем, какие типы эти переменные имеют
  • Вы можете легко добавлять новые переменные и/или изменить типы переменных, не меняя чтения код
  • Вы можете использовать этот код для чтения совершенно разные файлов, без написания нового кода для его

чтения как YAML

Если ваши потребности не так специфичны, как в вашем вопросе, я бы выбрал совершенно другой подход.

Я бы написал input.txt как файл yaml. В синтаксисе YAML это будет выглядеть следующим образом:

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

Вы можете прочитать его:

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

Будьте осторожны, если вы не контролируете файл input.txt, вы не контролируете, какие типы Паспорта будет. Я бы назвал файл input.yaml вместо input.txt. Если вы хотите узнать больше, о том, как писать файлы yaml, смотрите: http://yaml.kwiki.org/?YamlInFiveMinutes. Более подробную информацию о ямле и руби можно найти по адресу http://www.ruby-doc.org/stdlib/libdoc/yaml/rdoc/index.html.

0

Вы можете попробовать это. Не очень на одной линии, хотя:

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 
+0

Нецелесообразно вводить данные из внешних источников. В вашем случае ваш ввод может вызвать неожиданные методы. Вы даже не проверяете переменные своим кодом. Вы вызываете методы. Это работает только для общедоступных записываемых атрибутов, что может быть не всегда так, как нужно. Я предполагаю, что вопросник не хочет, чтобы все переменные были строками. С вашим кодом вы создаете только строки. – johannes

2

Предполагая, что файл действительно так регулярно, как ваш пример, вы можете чавкать все в хороший хэш, как это:

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

Это дает вам:

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

Но тогда вы действительно вам понадобится какой-то код, специфичный для конкретной операции, для того, чтобы сделать любую обработку типа, которую вы хотите, особенно для любого семейства.

Смежные вопросы