【问题标题】:Suggestion for python regex and selecting columns [duplicate]python regex和选择列的建议[重复]
【发布时间】:2014-06-09 20:36:52
【问题描述】:

如何选择,在以空格分隔的 3、4 或 X 列(不是恒定空格,而是每行上有多个空格)的文件中,使用正则表达式选择每行的前 2 列?

我的文件包括:IP [SPACES] Subnet_Mask [SPACES] NEXT_HOP_IP [NEW LINE]

所有行都使用该格式。如何仅提取前 2 列? (IP 和子网掩码)

这是一个尝试正则表达式的示例:

10.97.96.0 10.97.97.128 47.73.1.0
47.73.4.128 47.73.7.6 47.73.8.0
47.73.15.0   47.73.40.0   47.73.41.0
85.205.9.164 85.205.14.44 172.17.103.0
172.17.103.8 172.17.103.48 172.17.103.56
172.17.103.96         172.17.103.100       172.17.103.136
172.17.103.140 172.17.104.44            172.17.105.28
172.17.105.32       172.17.105.220      172.17.105.224

不要查看特定的 IP。我知道第二列不是由有效的地址掩码组成的。这只是一个例子。

我已经试过了:

(?P<IP_ADD>\s*[1-9][0-9]{1,2}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})(?P<space>\s*)(?P<MASK>[1-9][0-9]{1,2}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}(\s+|\D*))

但它并不完全有效......

【问题讨论】:

  • 这里为什么需要正则表达式?使用csv 模块或者只是用空格分割每一行。
  • 我需要某种“单线”。我不想打开文件,关闭它,ecc。需要一些“又快又脏”的东西。
  • 所以可以肯定的是,你想解析文件而不打开它?
  • 我的工作需要它。我没有时间总是传入文件或将所有文本保存在文件中。我只想放一些随机字符串并得到我想要的结果
  • 那么在来自重复链接的单行解决方案中,什么对您不起作用?多行?

标签: python regex parsing python-2.7


【解决方案1】:

用正则表达式:

如果您想获取前 2 列,无论它们包含什么,以及分隔它们的空间量,您可以使用 \S(匹配除空格之外的任何内容)和 \s(仅匹配空格)来实现:

import re
lines = """
    47.73.4.128 47.73.7.6 47.73.8.0
    47.73.15.0   47.73.40.0   47.73.41.0
    85.205.9.164 85.205.14.44 172.17.103.0
    172.17.103.8 172.17.103.48 172.17.103.56
    172.17.103.96         172.17.103.100       172.17.103.136
    172.17.103.140 172.17.104.44            172.17.105.28
    172.17.105.32       172.17.105.220      172.17.105.224
"""
regex = re.compile(r'(\S+)\s+(\S+)')
regex.findall(lines)

结果:

[('10.97.96.0', '10.97.97.128'),
 ('47.73.1.0', '47.73.4.128'),
 ('47.73.7.6', '47.73.8.0'),
 ('47.73.15.0', '47.73.40.0'),
 ('47.73.41.0', '85.205.9.164'),
 ('85.205.14.44', '172.17.103.0'),
 ('172.17.103.8', '172.17.103.48'),
 ('172.17.103.56', '172.17.103.96'),
 ('172.17.103.100', '172.17.103.136'),
 ('172.17.103.140', '172.17.104.44'),
 ('172.17.105.28', '172.17.105.32'),
 ('172.17.105.220', '172.17.105.224')]

没有正则表达式

如果您不想使用正则表达式,但仍然能够处理多个空格,您也可以这样做:

while '  ' in lines:  # notice the two-spaces-string
    lines = lines.replace('  ', ' ')
columns = [line.split(' ')[:2] for line in lines.split('\n') if line]

优点和缺点:

使用正则表达式的优点是,如果分隔符包含制表符,它也可以正确解析数据,而第二种解决方案不会出现这种情况。 另一方面,正则表达式比简单的字符串拆分需要更多的计算,这可能会对非常大的数据集产生影响。

【讨论】:

  • 这太棒了。太糟糕了,我只能选择 1 个最佳答案...谢谢你们的帮助!
  • 仅供参考,split() 已经处理了多个空格(请参阅doc),因此不需要while 循环,[\S]\S 相同,通常将原始字符串用于正则表达式的好习惯(而不是普通字符串,因为我记得很难:))即使这里不是技术上强制
  • 是的,但是没有 args 的拆分也会在换行符上拆分,这不是理想的行为(行之间没有区别)。关于正则表达式你是对的,我首先用[^\s] 写了它,忘记了括号。已编辑
  • 是的,但是由于您已经在\n 上进行了拆分,因此您基本上可以逐行工作。无论如何,这是一个很好的答案。
【解决方案2】:

它是一个班轮:

[s.split()[:2] for s in string.split('\n')]

示例

string = """10.97.96.0 10.97.97.128 47.73.1.0
47.73.4.128 47.73.7.6 47.73.8.0
47.73.15.0   47.73.40.0   47.73.41.0
85.205.9.164 85.205.14.44 172.17.103.0
172.17.103.8 172.17.103.48 172.17.103.56
172.17.103.96         172.17.103.100       172.17.103.136
172.17.103.140 172.17.104.44            172.17.105.28
172.17.105.32       172.17.105.220      172.17.105.224"""

print [s.split()[:2] for s in string.split('\n')]

输出

[['10.97.96.0', '10.97.97.128']
['47.73.4.128', '47.73.7.6']
['47.73.15.0', '47.73.40.0']
['85.205.9.164', '85.205.14.44']
['172.17.103.8', '172.17.103.48']
['172.17.103.96', '172.17.103.100']
['172.17.103.140', '172.17.104.44']
['172.17.105.32', '172.17.105.220']]

【讨论】:

  • 为什么使用正则表达式来分割换行符?使用string.split('\n') 的性能开销会小得多。
  • @MatToufoutu:你完全正确。我使用的是原始字符串,但不明白为什么 string.split(r'\n') 不起作用...谢谢!
【解决方案3】:

由于您需要“某种单线”,因此有很多方法不涉及 python。 也许:

| awk '{print $1,$2}'

在标准输出上产生您输入的任何内容。

【讨论】:

  • 问题是我在 Windows 上。
【解决方案4】:

已编辑以执行任意数量的空格匹配。

如果您知道这将是前 2 个空格分隔的值,您可以使用 python regular expressions 作为一个选项来完成此操作。

一个不错的regex cheat sheet 也将帮助您找到一些捷径。单词、空格和数字等特定标记类具有这些小快捷方式。

import re
line = "10.97.96.0 10.97.97.128 47.73.1.0"
result = re.split("\s+", line)[0:2]

result
['10.97.96.0', '10.97.97.128']

【讨论】:

  • 多个空格怎么样?我的字符串并不总是由 1 个空格分隔(参见示例)
  • 用 \s* 或 \s+ 替换 \s 以匹配多个空格
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-06-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-04
  • 1970-01-01
相关资源
最近更新 更多