在课程中学习Ruby(v.5.5)。 目标是在ruby简单解析器上编写,它将计算apache日志中大多数查询负责的IP主机。
Apache日志:
87.99.82.183 - - [01/Feb/2018:18:50:06 +0000] "GET /favicon.ico HTTP/1.1" 404 504 "http://35.225.14.147/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36"
87.99.82.183 - - [01/Feb/2018:18:50:52 +0000] "GET /secret.html HTTP/1.1" 404 505 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36"
Ruby代码:
class ApacheLogAnalyzer
def initialize
@total_hits_by_ip = {}
end
def analyze(file_name)
ip_regex = /^\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}/
file = File.open(file_name , "r")
file.each_line do |line|
count_hits(ip_regex.match(line))
end
end
def count_hits(ip)
if ip
if @total_hits_by_ip[ip]
@total_hits_by_ip[ip] += 1
else
@total_hits_by_ip[ip] = 1
end
end
end
结果如下:
{#<MatchData "87.99.82.183">=>1, #<MatchData "87.99.82.183">=>1}
结果包含重复项(它应包含一个键&#34; 87.99.82.183&#34;值为2)。问题出在哪里?
答案 0 :(得分:1)
结果在您的情况下包含重复项,因为散列键是不同的对象但具有相同的值。看看这个例子:
a = "hello world foo".match(/he/) # => #<MatchData "he">
b = "hello world bar".match(/he/) # => #<MatchData "he">
a == b # => false
例如,您可以使用字符串替换哈希键,以明确避免这种情况:
class ApacheLogAnalyzer
def analyze(file_name)
File.open(file_name).each_line.inject(Hash.new(0)) do |result, line|
ip = line.split
hash[ip] += 1
result
end
end
end
答案 1 :(得分:0)
感谢您的评论。我发现使用方法to_s解决了这个问题。 所以改进的代码看起来像这样:
count_hits(ip_regex.match(line).to_s)