简体   繁体   中英

How to grep for a pattern in a file and store the content following it?

My file content is

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

How can I grep for "Name", "Age", "Place" and store name "XYZ", age "30" and place "ABCD" in a hash?

What should be the '?' in this code to get those?

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
}

You can use something like this.

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

output

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

Strange code, but in this case:

  data[:name] = l.split(':')[1] if l.match(name)
when age
  data[:age] = l.split(':')[1] if l.match(age)
when place
  data[:place]= l.split(':')[1] if l.match(place)

Are you interested in refactoring?

One option is to:

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)

Suppose we first read the file into a string:

str = File.read('fname')

which is:

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

Then use the 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

with String#scan to form the hash:

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

I'd do something like this:

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 will create sub-arrays if it sees pattern groups in the regular expression. Those make it easy to turn the returned array of arrays into a hash.

If you need to fold the keys to lower-case, or convert them to symbols:

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"}

Or:

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"}

Or some variation on:

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"}

If the example string truly is the complete file, and there won't be any other reoccurrence of the key/value pairs, then this will work. If there could be more than one then the resulting hash will not be correct because the subsequent pairs will stomp on the first one. If the file is as you said, then it'll work fine.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM