2016-06-09 10 views
0

Mein Dateiinhalt istWie finde ich ein Muster in einer Datei und speichere den darauf folgenden Inhalt?

blablabla  
Name : 'XYZ' 
Age : '30' 
Place : 'ABCD'  
blablabla 

Wie kann ich für "Namen" grep "Alter", "Platz" und speichern Namen "XYZ", Alter "30" und Ort "ABCD" in einem Hash?

Was sollte das "?" in diesem Code, um diese zu bekommen?

data = {} 
name = /Name/ 
age = /Age/ 
place = /Place/ 
read_lines(file) { |l| 
    case l 
    when name 
     data[:name] = ? 
    when age 
     data[:age] = ? 
    when place 
     data[:place]= ? 
    end 
} 
+0

Wie viele Gruppen dieser Zeilen gibt es in der Datei? Nur einer, oder wird es viele geben? Wie groß sind die Dateien? –

Antwort

0

Sie können so etwas verwenden.

data = {} 
keys = {:name => "Name", :age => "Age", :place => "Place"} 

File.open("test.txt", "r") do |f| 
    f.each_line do |line| 
    line.chomp! 
    keys.each do |hash_key, string| 
     if line[/#{string}/] 
     data[hash_key] = line.strip.split(" : ")[-1].gsub("'", "") 
     break 
     end 
    end 
    end 
end 

Ausgang

p data 
# => {:name=>"XYZ", :age=>"30", :place=>"ABCD"} 
+0

Ruby hat eine Methode speziell zum Entfernen von Zeilenenden: 'String # chomp'. 'line.gsub! (" \ n "," ")' ist hier zu viel. –

+0

@ Jordan Thx für Beratung, bearbeitet –

+0

Es ist 'chomp!', Nicht 'hacken!'. –

0

Seltsame Code, aber in diesem Fall:

Sie in Refactoring interessiert?

Eine Option ist:

mapping = 
    [ 
     { name: :name, pattern: /Name/ }, 
     { name: :age, pattern: /Age/ }, 
     { name: :place, pattern: /Place/ } 
    ] 
data = str.split(/\r?\n|\r/).map do |line| 
    mapping.map{|pair| 
    { pair[:name] => line.split(' : ')[1].gsub("'", "") } if line.match(pair[:pattern]) 
    }.compact.reduce({}, :merge) 
end.reduce({}, :merge) 
+0

Warum verwenden Sie 'case' und nach wenn' if.match'? –

+0

Die Frage war, Fragezeichen zu füllen. Ich wette, dass Code im Allgemeinen neu geschrieben werden muss. –

+0

Ich stimme zu, aber ich frage nur, warum 'case' mit rgx verwendet werden soll und danach' if l.match';) –

0

Angenommen, wir zunächst die Datei in einen String lesen:

str = File.read('fname') 

das ist:

str =<<_ 
blablabla 
Name : 'XYZ' 
Age : '30' 
Place : 'ABCD' 
blablabla 
_ 
    #=> "blablabla\nName : 'XYZ'\nAge : '30'\nPlace : 'ABCD'\nblablabla\n" 

Dann nutzen Sie die regex

r =/
    ^     # match beginning of line 
    Name\s*:\s*'(.*)'\n # match 'Name`, ':' possibly surrounded by spaces, any number 
         # of any character in capture group 1, end of line 
    Age\s*:\s*'(.*)'\n # match 'Age`, ':' possibly surrounded by spaces, any number 
         # of any character in capture group 2, end of line 
    Place\s*:\s*'(.*)'\n # match 'Place`, ':' possibly surrounded by spaces, any number 
         # of any character in capture group 3, end of line 
    /x     # free-spacing regex definition mode 

mit String#scan den Hash bilden:

str = <<EOT 
blablabla  
Name : 'XYZ' 
Age : '30' 
Place : 'ABCD'  
blablabla 
EOT 

str.scan(/(Name|Age|Place)\s+:\s'([^']+)/).to_h # => {"Name"=>"XYZ", "Age"=>"30", "Place"=>"ABCD"} 

scan schaffen wird Subanordnungen wenn es Mustergruppen im regulären Ausdruck sieht:

[:name, :age, :place].zip(str.scan(r).first).to_h 
    #=> {:name=>"XYZ", :age=>"30", :place=>"ABCD"} 
0

ich so etwas tun würde. Diese machen es einfach, das zurückgegebene Array von Arrays in einen Hash umzuwandeln.

Wenn Sie die Schlüssel falten in Kleinbuchstaben, oder wandeln sie in Symbole:

str.scan(/(Name|Age|Place)\s+:\s'([^']+)/) 
    .map{ |k, v| [k.downcase, v] } # => [["name", "XYZ"], ["age", "30"], ["place", "ABCD"]] 
    .to_h # => {"name"=>"XYZ", "age"=>"30", "place"=>"ABCD"} 

Oder:

str.scan(/(Name|Age|Place)\s+:\s'([^']+)/) 
    .map{ |k, v| [k.downcase.to_sym, v] } # => [[:name, "XYZ"], [:age, "30"], [:place, "ABCD"]] 
    .to_h # => {:name=>"XYZ", :age=>"30", :place=>"ABCD"} 

oder eine Variation auf:

str.scan(/(Name|Age|Place)\s+:\s'([^']+)/) 
    .each_with_object({}){ |(k,v), h| h[k.downcase.to_sym] = v} 
# => {:name=>"XYZ", :age=>"30", :place=>"ABCD"} 

Wenn der Beispielstring ist wirklich die vollständige Datei, und es wird keine anderen Reocc sein der Schlüssel/Wert-Paare, dann wird dies funktionieren. Wenn es mehr als einen geben kann, wird der resultierende Hash nicht korrekt sein, da die nachfolgenden Paare auf dem ersten stampfen werden. Wenn die Datei wie gesagt ist, dann wird es funktionieren.