Python正则表达式和选择列的建议

1 投票
4 回答
3148 浏览
提问于 2025-04-18 04:05

我想知道怎么用正则表达式,从一个文件中选择每行的前两列,这个文件有3列、4列或者更多列,列与列之间是用空格分开的(这些空格不是固定的,而是每行可能有多个空格)。

我的文件格式是:IP [空格] 子网掩码 [空格] 下一跳IP [换行]

所有行都是这个格式。我想提取出前两列(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*))

但效果不是很好……

4 个回答

0

因为你需要“某种单行代码”,其实有很多方法可以做到,而不一定要用Python。比如:

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

你可以用任何能在标准输出(stdout)上输出你输入内容的东西。

0

编辑过的内容可以用来匹配任意数量的空格。

如果你知道要处理的内容是前两个用空格分开的值,可以使用Python的正则表达式来实现这个功能。

一个很不错的正则表达式速查表也能帮助你找到一些快捷的方法。像单词、空格和数字这样的特定符号类别都有一些小技巧。

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.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']]
1

使用正则表达式:

如果你想提取前两列,不管它们里面有什么内容,也不管它们之间有多少空格,你可以用 \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]

优缺点:

使用正则表达式的好处是,如果分隔符中包含制表符,它也能正确解析数据,而第二种方法就做不到这一点。另一方面,正则表达式比简单的字符串分割需要更多的计算,这在处理非常大的数据集时可能会有影响。

撰写回答