【问题标题】:Parsing XML using minidom with regex使用带有正则表达式的 minidom 解析 XML
【发布时间】:2013-01-08 22:42:32
【问题描述】:

我正在尝试解析一些 XML,寻找标签名称为“ip”的元素最终我需要一个包含 IP 地址的字符串列表。这是我尝试过的:

def parseHosts(xmldoc):
  hostsNode = xmldoc.firstChild
  xmlList = hostsNode.getElementsByTagName("ip")

  ipList = []
  for ip in xmlList:
    ipList.append(ip.childNodes[0].nodeValue)

  print ipList
>>>[u'172.16.60.92', u'172.16.60.89', u'\n              ', u'172.16.60.90', u'172.16.60.91', u'172.16.60.93']

没关系。但我需要一个 IP 地址字符串列表...我不希望节点为空。只是一个很好的地址列表,如下所示:

['172.16.60.1', '172.16.60.5', 172.16.60.100']

我尝试了一些带有列表理解的正则表达式

  regex = re.compile(r'172\.16\.[0-9]*\.[0-9]*')
  [m.group(0) for l in ipList for m in [regex.search(1)] if m]

但我收到以下错误

File "myParser.py", line 47, in parseHosts
[m.group(0) for l in ipList for m in [regex.search(1)] if m]
TypeError: expected string or buffer

尽我所能,我找不到类型 ipList 正在使用type(ipList),我也无法弄清楚如何将这些东西变成字符串。

另外...摆脱那些 Unicode 的东西会很好。

很明显,我已经走到了尽头,但我不知道该去哪里找。

【问题讨论】:

  • 您在哪里看到要删除的“uuencode 东西”?
  • 另外,你为什么不能使用type(ipList)?你希望它有什么好处呢?您将其创建为空的list,然后在其上调用append,那么除了list,它还能是什么?
  • uuencode 的东西在 ipList u'172.16.60.92'中
  • 那不是 uuencoded。 uuencoded 文本看起来像 'begin 666 <data>\n,,3<R+C$V+CDP+CDR\n \nend\n'。
  • 当我使用 type(ipList) 时,我什么也得不到。它没有告诉我它是字符串还是列表还是其他任何东西......我知道我创建了一个列表,但是有一个类型错误。那会在哪里?

标签: python xml regex unicode


【解决方案1】:

让我们回到您的原始代码。它以ipList 结束:

[u'172.16.60.92', u'172.16.60.89', u'\n              ', u'172.16.60.90', u'172.16.60.91', u'172.16.60.93']

这里唯一的问题是它包含了充满空格的字符串,以及带有 IP 地址的字符串,对吧?

所以,让我们在事后过滤它:

In [51]: ipList = [u'172.16.60.92', u'172.16.60.89', u'\n              ', u'172.16.60.90', u'172.16.60.91', u'172.16.60.93']

In [52]: ipList = [ip for ip in ipList if ip.strip()]

In [53]: ipList
Out[53]: 
['172.16.60.92',
 '172.16.60.89',
 '172.16.60.90',
 '172.16.60.91',
 '172.16.60.93']

你就完成了!

为什么会这样?好吧,ip.strip() 将删除左右两侧的所有空格。将结果粘贴到if 语句中,如果有任何剩余则为真,如果没有剩余则为假。

但显然您可以将相同的条件移回原始循环,将其放在append 调用之前,效果完全相同:

def parseHosts(xmldoc):
  hostsNode = xmldoc.firstChild
  xmlList = hostsNode.getElementsByTagName("ip")

  ipList = []
  for ip in xmlList:
    ipstr = ip.childNodes[0].nodeValue
    if ipstr.strip():
      ipList.append(ipstr)

但是整个ipList 部分显然只是列表理解的冗长版本,所以:

def parseHosts(xmldoc):
  hostsNode = xmldoc.firstChild
  xmlList = hostsNode.getElementsByTagName("ip")
  ipList = [ip.childNodes[0].nodeValue for ip in xmlList
            if ip.childNodes[0].nodeValue.strip()]

至于您尝试解决此问题:

[m.group(0) for l in ipList for m in [regex.search(1)] if m]

当嵌套列表推导的作用不是很明显时,将其分成两个推导。

但是让我们将其重写为显式循环。这不仅使它更易于理解,而且使调试更容易:

result = []
for l in ipList:
    for m in [regex.search(1)]:
        if m:
            result.append(m.group(0))

当你运行这个时,你会在第三行得到一个异常,这应该是显而易见的原因。

【讨论】:

  • 太棒了!谢谢...除了我没有提到列表中的某些 IP 可能不遵循我的正则表达式。我想要只有 172.16.*.*... 的 IP,所以我想我需要那个正则表达式。
  • @TheWellington:好的,您应该能够弄清楚如何添加它。只需将测试从您发布的问题中的简单测试更改为您真正想要使用正则表达式的测试。跨度>
  • 它一直有效,直到带有正则表达式的部分。我仍然得到 TypeError:预期的字符串或缓冲区。正则表达式对列表内容的类型有什么作用吗?
  • @TheWellington:什么名单?查看您传递给regex.search 的参数。 (顺便说一句,这正是您通常不想将变量命名为 l 的原因。)
  • @TheWellington:一旦你解决了这个问题:你为什么需要做for m in [anything]:?保证循环一次,将m 设置为anything。您可以通过执行m=anything 并删除循环来获得完全相同的效果。这是应该做其他事情,还是没有必要?
【解决方案2】:

你可以使用filter(regex.match,ipList):

import re
ipList=[u'172.16.60.92', u'172.16.60.89', u'\n              ', u'172.16.60.90', u'172.16.60.91', u'172.16.60.93']
regex = re.compile(r'172\.16\.[0-9]*\.[0-9]*')
filter(regex.match,ipList)

out:

[u'172.16.60.92',
 u'172.16.60.89',
 u'172.16.60.90',
 u'172.16.60.91',
 u'172.16.60.93']

【讨论】:

    猜你喜欢
    • 2012-01-25
    • 1970-01-01
    • 2015-04-29
    • 1970-01-01
    • 2011-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-13
    相关资源
    最近更新 更多