【问题标题】:Remove all characters between two words and replace with a space删除两个单词之间的所有字符并用空格替换
【发布时间】:2012-05-12 21:02:07
【问题描述】:

我正在使用 Python 3。我编写了两个程序。一个循环遍历 csv 文件以获取 Cisco 交换机的 IP 地址、登录、运行命令,然后将每个结果的结果输出到单独的文本文件。所以我最终得到了一些文本文件......每个开关一个。第二个程序使用 xlwt 将每个文本文件中的信息写入 Excel 中自己的工作表。

主要想法是我需要开发一份报告,显示服务中的端口。一旦我将这些导入 Excel,我就可以编写一些公式来提取我需要的数据。但就目前而言,当我将其导入 Excel 时,我必须手动删除一些单元格,因为所有内容都没有对齐,这是因为名称列中的某些单词之间存在空格(我正在导入 Excel以空格分隔)。我试图用字符串和列表方法(拆分、连接、切片等)做一些事情,但我无法得到我想要的。并且 Name 列在任何一种一致的约定中都没有标准化。我确实注意到虽然名称实际上可能很长,但它会被截断为一定数量的字符。

理想情况下,首先删除前 4 行(最顶部有空白行)和最后一行,然后对于 Port 和 Status 之间的任何内容,将其全部删除(完全删除包括标题在内的列)。

这是从交换机获取数据后文件的外观。

sw1#term 长度 0 sw1#显示接口状态 端口名称 状态 Vlan 双工速度类型 Gi0/1 Trunk to switch (a connected 1 a-full a-100 10/100/1000BaseTX Gi0/2 网络增强 pe 已连接 1 a-full a-1000 10/100/1000BaseTX Gi0/3 已连接 1 a-full a-1000 10/100/1000BaseTX Gi0/4 已连接 1 a-full a-100 10/100/1000BaseTX Gi0/5 notconnect 1 auto auto 不存在 Gi0/6 未连接 1 自动 自动 不存在 Gi0/7 未连接 1 自动 自动 不存在 Gi0/8 未连接 1 自动 自动 不存在 Gi0/9 未连接 1 自动 自动 不存在 Gi0/10 已连接 1 a-full a-100 10/100/1000BaseTX Gi0/11 notconnect 1 auto auto 不存在 Gi0/12 已连接 1 a-full a-100 10/100/1000BaseTX Gi0/13 禁用 1 自动 自动 不存在 Gi0/14 禁用 1 自动 自动 不存在 Gi0/15 禁用 1 自动 自动 不存在 Gi0/16 禁用 1 自动 自动 不存在 sw1#注销

我想要的最终结果如下。这应该允许行/列结构在导入 Excel 时保持不变。请注意,所有列信息都用空格分隔。我发现导入为固定宽度或以空格分隔,并将连续空格视为已选中似乎效果很好。

端口状态 Vlan 双工速度类型 Gi0/1 已连接 1 a-full a-100 10/100/1000BaseTX Gi0/2 已连接 1 a-full a-1000 10/100/1000BaseTX Gi0/3 已连接 1 a-full a-1000 10/100/1000BaseTX Gi0/4 已连接 1 a-full a-100 10/100/1000BaseTX Gi0/5 notconnect 1 auto auto 不存在 Gi0/6 未连接 1 自动 自动 不存在 Gi0/7 未连接 1 自动 自动 不存在 Gi0/8 未连接 1 自动 自动 不存在 Gi0/9 未连接 1 自动 自动 不存在 Gi0/10 已连接 1 a-full a-100 10/100/1000BaseTX Gi0/11 notconnect 1 auto auto 不存在 Gi0/12 已连接 1 a-full a-100 10/100/1000BaseTX Gi0/13 禁用 1 自动 自动 不存在 Gi0/14 禁用 1 自动 自动 不存在 Gi0/15 禁用 1 自动 自动 不存在 Gi0/16 禁用 1 自动 自动 不存在

任何指针将不胜感激。我在想正则表达式可能是有序的,但我需要一些帮助来构建它。我希望这不会太模棱两可。

删除了以前的更新并将其移至新线程

【问题讨论】:

  • 发布您目前拥有的代码。最初的想法是split() 完全有能力处理这个问题;跳过索引0 之后的所有内容,直到出现“已连接|未连接|已禁用”这个词;在那之后,一切看起来都与我一致......

标签: python cisco


【解决方案1】:
with open('file') as f:
    lines = f.readlines()
    lines = lines[-1:] + lines[2:-1]
    for line in lines:
        print line[0:11] + line[35:-1]

我认为这将大致满足您的要求;你可能需要玩一些数字,因为我自己没有运行它。它只使用列表(或字符串)索引:

  • list[x:] 是从 x 开始的所有条目
  • list[x:y] 是从 x 到 y 的所有条目
  • list[-x] 是从末尾算起的第 x 行

lines[-1:] + lines[2:-1] 把最后一行放在最前面,把前两行扔掉; line[0:11] + line[35:-1] 不包括您不想要的部分和最后的换行符。

更新如果你想写入一个新文件,而不是标准输出:

with open('infile') as in:
    with open('outfile', 'w') as out:
        lines = in.readlines()
        ...
            print(line[0:6] + line[28:-1], file=out)

事实上,由于 readlines 一次读取所有内容,您可以这样做:

with open('infile') as in:
    lines = in.readlines()
with open('outfile', 'w') as out:
    for line in lines:
        ....
        print(line[0:6] + line[28:-1], file=out)

因为不需要打开输入文件(with 完成时它会关闭)。

【讨论】:

  • 这个也很好用。对于我正在处理的文件,行 print (line[0:6] + line[28:-1]) 很好。现在把它放到一个新文件中。
  • 效果很好。我不得不对索引进行一些更改,但我不知道为什么。对于我测试的每个更改,我都使用相同的输入文件。我怀疑这与我打印到标准输出时看到的 \n 有关。无论如何,运行良好并删除文件的第一行和最后一行,并且在 Excel 中运行良好。
  • 删除最后一个 \n 的替代方法是使用 strip: line = line.strip() 删除换行符和任何尾随/开始空格。那么你就不需要删除最后一个字符了。
  • 安德鲁,我已经对此进行了一些工作,并发布了更新...如果您有任何建议,介意看看并回复吗?
  • 这是关于,, 的问题吗?就像其他部分一样,只需拉出该部分,但在字符串上调用.strip()。删除前导和尾随空格,因此会将没有数据的块缩小到没有。
【解决方案2】:

我跳过了前 3 行:

sw1#term length 0
sw1#show interfaces status

程序:

with open('in.txt') as f,open('out.txt','w') as out:
   line1=f.readline()
   ind1=line1.find('Name')
   ind2=line1.find('Status')
   x=line1.split()
   x.remove('Name')
   y="%-13s %-15s %-6s %-7s %-8s %-s"%(x[0],x[1],x[2],x[3],x[4],x[5])
   out.write(y+'\n')
   for x in f:
       x=x[:ind1]+x[ind2:]
       x=x.split()
       y="%-13s %-15s %-6s %-7s %-8s %-s"%(x[0],x[1],x[2],x[3],x[4],x[5])
       out.write(y+'\n')


Port          Status          Vlan   Duplex  Speed    Type
Gi0/1         connected       1      a-full  a-100    10/100/1000BaseTX
Gi0/2         connected       1      a-full  a-1000   10/100/1000BaseTX
Gi0/3         connected       1      a-full  a-1000   10/100/1000BaseTX
Gi0/4         connected       1      a-full  a-100    10/100/1000BaseTX
Gi0/5         notconnect      1      auto    auto     Not
Gi0/6         notconnect      1      auto    auto     Not
Gi0/7         notconnect      1      auto    auto     Not
Gi0/8         notconnect      1      auto    auto     Not
Gi0/9         notconnect      1      auto    auto     Not
Gi0/10        connected       1      a-full  a-100    10/100/1000BaseTX
Gi0/11        notconnect      1      auto    auto     Not
Gi0/12        connected       1      a-full  a-100    10/100/1000BaseTX
Gi0/13        disabled        1      auto    auto     Not
Gi0/14        disabled        1      auto    auto     Not
Gi0/15        disabled        1      auto    auto     Not
Gi0/16        disabled        1      auto    auto     Not

【讨论】:

  • 我一直在使用这里提供的几种解决方案,但我似乎能够复制并产生良好的结果。但我无法将结果写入文件。通常,因为这就是我所知道的,所以我打开一个文件进行写入,并在 f 中执行典型的 for 行:f.write(line)。或者该构造的一些迭代。我已经非常擅长打开现有文件并将其一些内容写入新文件。在这种情况下,变量 x 包含我要写入文件的数据。所以类似于第 i 行 x: open('newfile', 'w').write(x) ?
  • 感谢大家的回复,显然我是新手,但这对我来说是一个很好的学习机会。从到目前为止我得到的建议中,我知道我还有多少需要学习。
  • @Shane 我编辑了解决方案,现在输出将写入文本文件。
  • 啊,我明白了。通过此编辑,您将结果存储在 y 中并可以从那里写入。我试图在 x=x.split() 之后写 x。而且我不知道可以像那样“即时”打开和写入文件。凉爽的。您不必关闭文件也很有趣。此代码确实有效,并且导入 Excel 看起来不错。
  • 我已经发布了更新,您介意查看并提供任何建议吗?
【解决方案3】:

首先,下面的代码删除了名称列。从那里取出并添加一个漂亮的 csv 打印输出。提示:column[-1] 是最后一个条目,column[-2] 是倒数第二个。如果存在字符串Not,则加入这些...

#!/usr/bin/env python

tokens = ['connected', 'notconnect', 'disabled']

with open('text') as fd:
    for line in fd:
        line = line.strip().split()

        connection = [line[0]]
        found = False

        for i in line:
            if i in tokens:
                found = True
            if found:
                connection.append(i)

        print connection

输出:

['Gi0/1', 'connected', '1', 'a-full', 'a-100', '10/100/1000BaseTX']
['Gi0/2', 'connected', '1', 'a-full', 'a-1000', '10/100/1000BaseTX']
['Gi0/3', 'connected', '1', 'a-full', 'a-1000', '10/100/1000BaseTX']
['Gi0/4', 'connected', '1', 'a-full', 'a-100', '10/100/1000BaseTX']
['Gi0/5', 'notconnect', '1', 'auto', 'auto', 'Not', 'Present']
['Gi0/6', 'notconnect', '1', 'auto', 'auto', 'Not', 'Present']
['Gi0/7', 'notconnect', '1', 'auto', 'auto', 'Not', 'Present']
['Gi0/8', 'notconnect', '1', 'auto', 'auto', 'Not', 'Present']
['Gi0/9', 'notconnect', '1', 'auto', 'auto', 'Not', 'Present']
['Gi0/10', 'connected', '1', 'a-full', 'a-100', '10/100/1000BaseTX']
['Gi0/11', 'notconnect', '1', 'auto', 'auto', 'Not', 'Present']
['Gi0/12', 'connected', '1', 'a-full', 'a-100', '10/100/1000BaseTX']
['Gi0/13', 'disabled', '1', 'auto', 'auto', 'Not', 'Present']
['Gi0/14', 'disabled', '1', 'auto', 'auto', 'Not', 'Present']
['Gi0/15', 'disabled', '1', 'auto', 'auto', 'Not', 'Present']
['Gi0/16', 'disabled', '1', 'auto', 'auto', 'Not', 'Present']

评论后更新:

这就是我使用KISS principle 的方式:

#!/usr/bin/env python

import sys

tokens = ['connected', 'notconnect', 'disabled']

with open('text') as fd:
    for line in fd:
        line = line.strip().split()

        connection = [line[0]]
        found = False

        for i in line:
            if i in tokens:
                found = True
            if found:
                connection.append(i)

        if 'Not' in connection and 'Present' in connection:
            # Remove last 2 entries
            connection.pop() ; connection.pop()
            connection.append('Not Present')

        print connection

输出:

['Gi0/1', 'connected', '1', 'a-full', 'a-100', '10/100/1000BaseTX']
['Gi0/2', 'connected', '1', 'a-full', 'a-1000', '10/100/1000BaseTX']
['Gi0/3', 'connected', '1', 'a-full', 'a-1000', '10/100/1000BaseTX']
['Gi0/4', 'connected', '1', 'a-full', 'a-100', '10/100/1000BaseTX']
['Gi0/5', 'notconnect', '1', 'auto', 'auto', 'Not Present']
['Gi0/6', 'notconnect', '1', 'auto', 'auto', 'Not Present']
['Gi0/7', 'notconnect', '1', 'auto', 'auto', 'Not Present']
['Gi0/8', 'notconnect', '1', 'auto', 'auto', 'Not Present']
['Gi0/9', 'notconnect', '1', 'auto', 'auto', 'Not Present']
['Gi0/10', 'connected', '1', 'a-full', 'a-100', '10/100/1000BaseTX']
['Gi0/11', 'notconnect', '1', 'auto', 'auto', 'Not Present']
['Gi0/12', 'connected', '1', 'a-full', 'a-100', '10/100/1000BaseTX']
['Gi0/13', 'disabled', '1', 'auto', 'auto', 'Not Present']
['Gi0/14', 'disabled', '1', 'auto', 'auto', 'Not Present']
['Gi0/15', 'disabled', '1', 'auto', 'auto', 'Not Present']
['Gi0/16', 'disabled', '1', 'auto', 'auto', 'Not Present']

【讨论】:

  • 我有您的解决方案,正如您所解释的那样,但是当我尝试加入“不”时,“现在”我无法弄清楚。我可以做类似于 ' '.join(line[-2:]) 的事情,但我不能让它适用于所有行。另外,这对您来说可能很明显,我最终得到了“不存在”,其他所有内容都被删除了。我已经尝试过 for 循环和几个加入练习,所以它不是完全陌生的。我似乎无法复制您为删除名称列所做的事情。你能再给我一个指点吗?
  • @Shane - 已更新,抱歉回复晚了!
  • 感谢您的宝贵时间。这很好用。我在努力做到这一点时学到了很多东西,所以即使我无法自拔,我也会带走很多东西。我尝试了很多不同的东西。看到有很多方法可以用 Python 做事,真是太酷了。顺便说一句,我希望使用 csv 合并您的解决方案,因为我发现虽然其他一些解决方案的组合根据开关类型起作用,但每列中或多或少的字符要处理。您的方法涉及使用 csv,所以我认为会更好。
  • 一旦我获得足够的声望点,我就会回来投票,因为这绝对有帮助。
  • Fredrik,我已经发布了一个更新,并且对您的任何输入感兴趣。
【解决方案4】:

如果类型不存在,我们只取第一个和最后 5 个值,并做一点大小写切换:

print "{:10} {:15} {:5} {:6} {:6} {}".format("port", "status", "vlan", "duplex", "speed", "type")
with open(my_filename) as logfile:
    content = logfile.read()
    for line in content.splitlines()[4:]:
        port = line.split()[0]
        if line.strip().endswith("Not Present"):
            itype = "Not Present"
            status, vlan, duplex, speed = line.split()[-6:-2]
        else:
            status, vlan, duplex, speed, itype = line.split()[-5:]
        print "{:10} {:15} {:5} {:6} {:6} {}".format(port, status, vlan, duplex, speed, itype)

产量:

port       status          vlan  duplex speed  type            
Gi0/1      connected       1     a-full a-100  10/100/1000BaseTX
Gi0/2      connected       1     a-full a-1000 10/100/1000BaseTX
Gi0/3      connected       1     a-full a-1000 10/100/1000BaseTX
Gi0/4      connected       1     a-full a-100  10/100/1000BaseTX
Gi0/5      notconnect      1     auto   auto   Not Present
Gi0/6      notconnect      1     auto   auto   Not Present
Gi0/7      notconnect      1     auto   auto   Not Present
Gi0/8      notconnect      1     auto   auto   Not Present
Gi0/9      notconnect      1     auto   auto   Not Present
Gi0/10     connected       1     a-full a-100  10/100/1000BaseTX
Gi0/11     notconnect      1     auto   auto   Not Present
Gi0/12     connected       1     a-full a-100  10/100/1000BaseTX
Gi0/13     disabled        1     auto   auto   Not Present
Gi0/14     disabled        1     auto   auto   Not Present
Gi0/15     disabled        1     auto   auto   Not Present
Gi0/16     disabled        1     auto   auto   Not Present

【讨论】: