繁体   English   中英

如何grep在文件中查找模式并在其后存储内容?

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

我的文件内容是

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

我该如何为“名称”,“年龄”,“地点”和商店名称“ XYZ”,年龄“ 30”以及“ ABCD”放置在哈希表中?

什么是“?” 在这段代码中得到那些?

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
}

您可以使用类似这样的东西。

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

输出

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

奇怪的代码,但在这种情况下:

  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)

您对重构感兴趣吗?

一种选择是:

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)

假设我们首先将文件读取为字符串:

str = File.read('fname')

这是:

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

然后使用正则表达式

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

String#scan形成哈希:

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

我会做这样的事情:

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将创建子数组。 这些使将返回的数组数组转换为哈希值变得容易。

如果需要将键折叠为小写或将其转换为符号:

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

要么:

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

或一些变化:

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

如果示例字符串确实是完整的文件,并且键/值对不会再出现任何其他情况,那么它将起作用。 如果可能不止一个,那么生成的哈希将是不正确的,因为随后的配对将在第一个配对上脚。 如果文件如您所说,则可以正常工作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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