Ruby - 循环访问多个字符串和填充数组时出现问题



我有一个包含以下字符串的response变量:

response变量(这个输出是我从telnet会话中提取的,为了简化起见,我没有在下面的代码中显示):

mydummyhost# show ip bgp 43.245.43.105
BGP routing table entry for 43.245.43.0/24
Paths: (2 available, best #1, table Default-IP-Routing-Table)
Not advertised to any peer
38561 2914 55432, (aggregated by 55532 202.68.67.134)
202.158.215.44 from 201.158.202.44 (202.158.215.62)
Community: 7575:1002 7575:2462 7575:3002 7575:6001 7575:8001
Last update: Tue Sep 22 12:25:17 2020
38561 2914 55433, (aggregated by 55433 202.68.67.135)
202.158.215.52 from 202.158.215.52 (202.158.215.62)
Community: 7575:1002 7575:2462 7575:3002 7575:6001 7575:8001
Last update: Mon Sep 21 06:44:58 2020

我有一段代码,我正在使用它来尝试遍历上面的字符串行,基本上得到以下结果:

所需结果:

43.245.43.105 is domestic peering (On-Net) originated by AS 55432 via path 38561 2914 55432
43.245.43.105 is domestic peering (On-Net) originated by AS 55433 via path 38561 2914 55433

法典:

#!/usr/bin/env ruby
require 'net/telnet'
ipaddress = "43.245.43.105"
cat = []
response = ""
origin = []
paths = []
net = []
community = []
onoffnet= {
ond:"domestic (On-Net)",
oni:"international research (On-Net)",
opd:"domestic peering (On-Net)",
ofd:"domestic transit (Off-Net)",
opi:"international peering (Off-Net)",
ofi:"international transit (Off-Net)"
}
response.each_line do |line|
if line  =~ /BGP routing table entry for (d+.d+.d+.d+.*)/
net[i] = $1
elsif line =~ /Community: (.*)$/
community[i] =  $1
elsif line  =~ /^s+([0-9 ]+),.*/
paths, aggregatedBy = line.split(", ")
paths[i] = paths.strip
origin[i] == aggregatedBy.split(" ")[2]
elsif line =~ /Last update:/
i += 1
end
end
if i == 0
print "ERROR, no data found for the IP."
else
i = 0
net.each do | ip |
if community[i] =~ /7575:1000/
cat[i] = onoffnet.fetch(:ond)
elsif community[i] =~ /7575:1001/
cat[i] = onoffnet.fetch(:oni)
elsif community[i] =~ /7575:1002/
if community[i] =~ /7575:6001/
cat[i] = onoffnet.fetch(:opd)
else
cat[i] = onoffnet.fetch(:opi)
end
elsif community[i] =~ /7575:1003/
if community[i] =~ /7575:6001/
cat[i] = onoffnet.fetch(:ofd)
else
cat[i] = onoffnet.fetch(:ofi)
end
end
i += 1

if origin[i].to_s.length > 0 && paths[i].to_s.length > 0
puts "#{ipaddress} is cat[i] network ip[i] originated by AS #{origin} via path #{paths} ."
else
puts #{ipaddress} + "is" +  cat[i] + "network" + ip[i] + "n"
puts "Test"
end
end
end

当我运行这个时,只有"测试"显示为输出:

[root@mydummyhost]# ./telnet.rb
Test

基本上,我正在尝试使用line =~ /Last update:/来确定我有另一个单独的路径和原点要通过递增i来显示,如果这有意义的话。

所以我知道它已经达到了if条件,但是我不确定为什么它没有显示第一个打印行puts #{ipaddress} + "is" + cat[i] + "network" + ip[i] + "n",这似乎是空的。

编辑:

puts #{ipaddress} + "is" + cat[i] + "network" + ip[i] + "n"更改为puts "#{ipaddress} is #{cat[i]} network #{ip[i]}n"后(如@trueunlessfalse建议的,谢谢!),我现在可以看到一个输出:

[root@dummyhost]# ./telnet.rb
43.245.43.105 is  network 3

不幸的是,这甚至没有接近我正在寻找的所需结果。

我知道问题出在我迭代该responsevar 并填充数组的方式上 - 我有一个有效的 perl 代码并试图将其转换为 ruby - ,我只是不确定如何解决这个问题或什么是更好的方法来完成该输出。

任何建议我应该如何迭代response以便可以根据Last update:标记的"块"末尾递增的i值填充数组?

谢谢 J

预期结果似乎取决于给定字符串中包含的以下类型的值:

  • BGP ip(例如,"43.245.43.105")
  • 路径值(例如,"38561 2914 55432")
  • 原始值(例如,"38561")
  • 社区价值观(例如,"7575:1002 7575:2462 7575:3002 7575:6001 7575:8001")

我建议您首先专注于提取这些值,然后构造所需的字符串相当简单。我的回答仅限于这个初始任务。

为了产生一些数字,我将首先构造您的字符串response

response =<<~BITTER_END
mydummyhost# show ip bgp 43.245.43.105
BGP routing table entry for 43.245.43.0/24
Paths: (2 available, best #1, table Default-IP-Routing-Table)
Not advertised to any peer
38561 2914 55432, (aggregated by 55532 202.68.67.134)
202.158.215.44 from 201.158.202.44 (202.158.215.62)
Community: 7575:1002 7575:2462 7575:3002 7575:6001 7575:8001
Last update: Tue Sep 22 12:25:17 2020
38561 2914 55433, (aggregated by 55433 202.68.67.135)
202.158.215.52 from 202.158.215.52 (202.158.215.62)
Community: 7575:1002 7575:2462 7575:3002 7575:6001 7575:8001
Last update: Mon Sep 21 06:44:58 2020
BITTER_END

我对Telnet了解不多,但它似乎包含response数据块,该块以"mydummyhost"开头的行开头。我写这个是为了允许多个这样的块(每个块都以一行开头,'mydummyhost'),所以作为第一步,我将应用带有正则表达式的 String#scan,如下所示。

arr = response.scan(/^mydummyhostD+.+?(?=z|^mydummyhost)/m)
#=> ["mydummyhost# show ip bgp 43.245.43.105nBGP routing table entry for 43.245.43.0/24nPaths: (2 available, best #1, table Default-IP-Routing-Table)n  Not advertised to any peern  38561 2914 55432, (aggregated by 55532 202.68.67.134)n    202.158.215.44 from 201.158.202.44 (202.158.215.62)n      Community: 7575:1002 7575:2462 7575:3002 7575:6001 7575:8001n      Last update: Tue Sep 22 12:25:17 2020nn  38561 2914 55433, (aggregated by 55433 202.68.67.135)n    202.158.215.52 from 202.158.215.52 (202.158.215.62)n      Community: 7575:1002 7575:2462 7575:3002 7575:6001 7575:8001n      Last update: Mon Sep 21 06:44:58 2020n"]

我们可以在自由间距模式下编写正则表达式以使其自我记录。

/
^mydummyhostD+   # match 'mydummyhost' at the beginning of a line followed
# by 1+ characters other than digits (D)
.+                # match 1+ characters, including line terminators
?                 # make previous match lazy (aka non-greedy)
(?=               # begin a positive lookahead
z              # match end of string
|               # or
^mydummyhost    # match '^mydummyhost' at the beginning of a line
)                 # end positive lookahead
/mx               # specify multiline (m) and free-spacing regex definition modes

多行模式(其他语言的名称不同)使点匹配行终止符( 和 \r)以及其他字符。

您将在此处看到arr包含一个元素。下一步是将arr映射到每个块的值。为了简化表示,我将假设字符串包含一个块,即response,但应该很明显它如何被推广。

提取 BGP IP

bgp_rgx = /^mydummyhostD+Kd{1,3}(?:.d{1,3}){3}$/
bgp_ip = response[bgp_rgx]
#=> "43.245.43.105"

请参阅字符串#[]。自由间距模式下的正则表达式:

bgp_rgx =
/
^mydummyhostD+ # match 'mydummyhost' at the begining of a line (^),
# followed by 1+ characters other than digits (D)
K              # reset the beginning of the match to the current location
# and discard any previously-matched characters from the
# match that is returned
d{1,3}         # match 1-3 digits
(?:.d{1,3})   # match '.' followed by 1-3 characters, save to a
# non-capture group 
{3}             # execute the foregoing non-capture group 3 times
$               # match end of line
/x              # specify free-spacing regex definition mode

提取路径值

path_rgx = /(?<=^ {2})d+(?: +d+){2}(?=,)/
paths = response.scan(path_rgx)
#=> ["38561 2914 55432", "38561 2914 55433"] 

在自由间距模式下:

path_rgx =
/
(?<=^[ ]{2})     # use a positive lookbehind (?<=...) to assert that the
# match that follows is preceded by two spaces at the
# beginning of a line
d+              # match 1+ digits
(?:[ ]+d+)      # match 1+ spaces followed by 1+ digits, save to non-capture group 
{2}              # execute the foregoing non-capture group 2 times
(?=,)            # use a positive lookahead (?=...) to assert that the
# preceding match is followed by ','
/x               # specify free-spacing regex definition mode

请注意,在自由间距模式下编写正则表达式时,在解析表达式之前会删除所有空格。因此,有必要保护所有不应被剥离的空间。我通过将空格字符放在捕获组中([ ])中来做到这一点。还有其他方法可以保护空间,但这并不重要。

从路径值中提取原始值

originated = paths.map { |s| s[/d+/] }
#=> ["38561", "38561"]

正则表达式显示"匹配一个或多个数字"。

提取社区价值

community_rgx = /^ {6}Community: +Kd+:d+(?: +d+:d+)+/
community = response.scan(community_rgx)
#=> ["7575:1002 7575:2462 7575:3002 7575:6001 7575:8001",
#    "7575:1002 7575:2462 7575:3002 7575:6001 7575:8001"]

在自由间距模式下:

community_rgx =
/
^[ ]{6}          # match 6 spaces at beginning of a line
Community:[ ]+   # match 'Community:' followed by 1+ spaces
K               # reset the beginning of the match to the current location
# and discard any previously-matched characters from the
d+:d+          # match 1+ digits, ':', 1+ digits
(?:[ ]+d+:d+)  # match 1+ spaces, 1+ digits, ':', 1+ digits, save 
# to a non-capture group
+                # execute the foregoing non-capture group 1+ times
/x               # specify free-spacing regex definition mode

将值合并到哈希中(可选)

params = {
bgp_ip: bgp_ip,
values: originated.zip(paths, community).map do |o,p,c|
{ originated: o, path: p, community: c }
end
}
#=> {:bgp_ip=>"43.245.43.105",
#    :values=>[
#      {:originated=>"38561", :path=>"38561 2914 55432",
#         :community=>"7575:1002 7575:2462 7575:3002 7575:6001 7575:8001"},
#      {:originated=>"38561", :path=>"38561 2914 55433",
#       :community=>"7575:1002 7575:2462 7575:3002 7575:6001 7575:8001"}
#    ]
#   }

请参阅数组#zip。

同样,如果字符串包含多个块,则会返回哈希数组,例如params

更新:这个答案并没有解决作者代码的所有问题,而只是为什么其中一个puts没有给出任何输出的问题。

我本来会预料到这一行:

puts #{ipaddress} + "is" +  cat[i] + "network" + ip[i] + "n"

抛出错误,因为我以前从未尝试在不先打开字符串的情况下插入字符串。

我在控制台中尝试过这个,实际上它只是打印了一个空行:

irb(main):002:0> a = "foo"
=> "foo"
irb(main):003:0> puts #{a}
=> nil

但是,这按预期工作:

irb(main):004:0> puts "#{a}"
foo
=> nil

尝试将此行重写为:

puts "#{ipaddress} is #{cat[i]} network #{ip[i]}n"

最新更新