背景
我有一个包含不规则数据的~10,000个列表的列表,需要将其转换为特定格式。转换后,这些数据将被摄入到pandas数据帧中。
TL / DR; 如何在列表中优雅地转换以下正则表达式的匹配字符串?
正则表达式 '\ d {1,3} - \ d {1,3},\ d {1,3} - \ d {1,3}'
示例: '1-3,6-8'到'1 2 3 6 7 8'
当前解决方案: 使用列表推导需要多个类型转换来转换字符串,并且不适合作为持久解决方案。
pat = re.compile('\d{1,3}-\d{1,3},\d{1,3}-\d{1,3}')
row = ['sss-www,ddd-eee', '1-3,6-8', 'XXXX', '0-2,3-7','234','1,5']
lst = [((str(list(range(int(x.split(',')[0].split('-')[0]),
int(x.split(','[0].split('-')[1])+1))).strip('[]').replace(',', '')+' '
+str(list(range(int(x.split(',')[1].split('-')[0]),
int(x.split(',')[1].split('-')[1]) + 1))).strip('[]').replace(',', '')))
if pat.match(str(x)) else x for x in row]
结果
['sss-www,ddd-eee', '1 2 3 6 7 8', 'XXXX', '0 1 2 3 4 5 6 7', '234', '1,5']
答案 0 :(得分:1)
抓住群组会更容易。
然后将组列表转换为整数,并在列表推导中逐个处理它们,与itertools.chain
链接
import re,itertools
pat = re.compile('(\d{1,3})-(\d{1,3}),(\d{1,3})-(\d{1,3})')
z='1-3,6-8'
groups = [int(x) for x in pat.match(z).groups()]
print(list(itertools.chain(*(list(range(groups[i],groups[i+1]+1)) for i in range(0,len(groups),2)))))
结果:
[1, 2, 3, 6, 7, 8]
不确定你是否会称之为#34;优雅"它仍然很复杂,主要是因为大多数对象返回需要明确转换为list
的生成器。
答案 1 :(得分:1)
有几种方法可以做到这一点,这是我的:
import re
txt = '1-3,6-8'
# Safer to use a raw string
pat = re.compile(r'(\d{1,3})-(\d{1,3}),(\d{1,3})-(\d{1,3})')
m = pat.match(txt)
if m:
start1, end1, start2, end2 = m.groups()
result = [i for i in range(int(start1), int(end1)+1)]
result += [i for i in range(int(start2), int(end2)+1)]
print(result)
给出:
[1, 2, 3, 6, 7, 8]
我在这里假设Python 3(如问题中所述)。
Python 2可以使用:
result = range(int(start1), int(end1)+1)
result += range(int(start2), int(end2)+1)
答案 2 :(得分:1)
我假设你也想处理更长的序列,比如1-10,15,23-25
?你真的不需要正则表达式,常规字符串处理函数也能正常工作。
def parse_sequence(seq):
result = []
for part in seq.split(','):
points = [int(s) for s in part.split('-')]
if len(points) == 2:
result.extend(range(points[0], points[1]+1))
elif len(points) == 1:
result.append(points[0])
else:
raise ValueError('invalid sequence')
return result
答案 3 :(得分:0)
取决于您期望看到的确切数据。一般来说,最好的方法是编写一个以块的形式解析字符串的函数。类似的东西:
def parse(string):
chunks = string.split(',')
for chunk in chunks:
match = re.match('(\d+)-(\d+)', chunk)
if match:
start = int(match.group(1))
end = int(match.group(2))
yield range(start:end+1)
else:
yield int(chunk)
答案 4 :(得分:0)
这是我的解决方案:
import re
from itertools import chain
s = '1-3, 6 - 8, 12-14, 20 -22'
rslt = list(chain(*[range(int(tup[0]), int(tup[1]) + 1)
for tup in re.findall(r'(\d+)\s*?-\s*?(\d+)', s)]))
输出:
In [43]: rslt
Out[43]: [1, 2, 3, 6, 7, 8, 12, 13, 14, 20, 21, 22]
一步一步:
In [44]: re.findall(r'(\d+)\s*?-\s*?(\d+)', s)
Out[44]: [('1', '3'), ('6', '8'), ('12', '14'), ('20', '22')]
In [45]: [range(int(tup[0]),int(tup[1])+1) for tup in re.findall(r'(\d+)\s*?-\s*?(\d+)', s)]
Out[45]: [range(1, 4), range(6, 9), range(12, 15), range(20, 23)]
答案 5 :(得分:0)
s_tmp = s.split(",")
[*range(x.split("-")int([0]),x.split("-")int(x[1])) for x in s_tmp]
如果存在语法错误,请道歉。我是通过手机输入的。基本上拆分,然后拆分 - 然后解压缩范围
中的条目