使用 python 正则表达式提取列表中的元素
Regex extract element in a list using python
我有一个包含一组文件历史记录的列表。我需要将列表中的每个元素分成几列并将其保存到 CSV
文件中。
我需要的列是 commit_id, filename, committer, date, time, line_number, code
。
假设,这是我的清单:
my_list = [
'f5213095324 master/ActiveMasterManager.java (Michael Stack 2010-08-31 23:51:44 +0000 1) /**',
'f5213095324 master/ActiveMasterManager.java (Michael Stack 2010-08-31 23:51:44 +0000 2) *',
'f5213095324 master/ActiveMasterManager.java (Michael Stack 2010-08-31 23:51:44 +0000 3) * Licensed to the Apache Software Foundation (ASF) under one',
'f5213095324 master/ActiveMasterManager.java (Michael Stack 2010-08-31 23:51:44 +0000 4) * or more contributor license agreements.',
...
'b5cf8748198 master/ActiveMasterManager.java (Michael Stack 2012-09-27 05:40:09 +0000 160) if (ZKUtil.checkExists(this.watcher, backupZNode) != -1) {'
]
所需的csv
输出:
commit_id | filename | committer | date | time | line_number | code
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
f5213095324 | master/ActiveMasterManager.java | Michael Stack | 2010-08-31 | 23:51:44 | 1 | /**
f5213095324 | master/ActiveMasterManager.java | Michael Stack | 2010-08-31 | 23:51:44 | 2 | *
f5213095324 | master/ActiveMasterManager.java | Michael Stack | 2010-08-31 | 23:51:44 | 3 | * Licensed to the Apache Software Foundation (ASF) under one
f5213095324 | master/ActiveMasterManager.java | Michael Stack | 2010-08-31 | 23:51:44 | 4 | * or more contributor license agreements.
........
b5cf8748198 | master/ActiveMasterManager.java | Michael Stack | 2012-09-27 | 05:40:09 | 160 | if (ZKUtil.checkExists(this.watcher, backupZNode) != -1) {
我尝试使用此代码:
pattern = re.compile(r'(?P<commit_id>\w+)\s+(?P<filename>[^\s]+)\s+\((?P<committer>.+)\s+(?P<date>\d{4}-\d\d-\d\d)\s+(?P<time>\d\d:\d\d:\d\d).+(?P<line_number>\b\d+\b)\)\s+(?P<code>[^"]*)')
with open('somefile.csv', 'w+', newline='') as f:
writer = csv.writer(f)
writer.writerow(['commit_id', 'filename', 'committer', 'date', 'time', 'line_number', 'code'])
for line in my_list:
writer.writerow([field.strip() for field in pattern.match(line).groups()])
总的来说,代码有效。
但是对于 line number = 160
,它在 line_number
列中写为 -1
,在 code
列中仅写为 {
。
正则表达式中是否缺少某些内容?
我修复了正则表达式。
这应该有效:
pattern = re.compile(r'(?P<commit_id>\w+)\s+(?P<filename>[^\s]+)\s+\((?P<committer>.+)\s+(?P<date>\d{4}-\d\d-\d\d)\s+(?P<time>\d\d:\d\d:\d\d).+?(?P<line_number>\b\d+\b)\)\s+(?P<code>[^"]*)')
我添加了一个问号以使用惰性匹配
".+" => ".+?"
不完全是您要找的,但这可能很有用。
import re
for row in my_list:
print([x.strip() for x in re.split(r"(?![)])\s+(?![(])", row)])
out:
['f5213095324', 'master/ActiveMasterManager.java', '(Michael', 'Stack', '2010-08-31', '23:51:44', '+0000', '1)', '/**']
['f5213095324', 'master/ActiveMasterManager.java', '(Michael', 'Stack', '2010-08-31', '23:51:44', '+0000', '2)', '*']
...
您的模式的主要问题是 .+
的使用。如果用 .*?
替换它,您不仅可以解决行号问题,还可以解决提交者姓名后的空格问题:
pattern = re.compile(r'(?P<commit_id>\w+)\s+(?P<filename>[^\s]+)\s+\((?P<committer>.*?)\s+(?P<date>\d{4}-\d\d-\d\d)\s+(?P<time>\d\d:\d\d:\d\d).*?(?P<line_number>\b\d+\b)\)\s+(?P<code>[^"]*)')
https://regex101.com/r/f7zjpA/2
编辑:
您没有提到要保留缩进,而且您的代码看起来并不像您真正想要的那样。 Whitespaces/indentations 之前的代码被删除不仅是因为正则表达式模式。有两件事:
在正则表达式模式中,您在 code
组之前使用了 \s+
,这排除了所有 whitespaces/indentations。如果你想保留它们,将 \s+
替换为 \s
,这将只捕获第一个而不是所有的:
pattern = re.compile(r'(?P<commit_id>\w+)\s+(?P<filename>[^\s]+)\s+\((?P<committer>.*?)\s+(?P<date>\d{4}-\d\d-\d\d)\s+(?P<time>\d\d:\d\d:\d\d).*?(?P<line_number>\b\d+\b)\)\s(?P<code>[^"]*)')
在 for 循环中,您使用 field.strip()
删除字符串开头和结尾处的所有空格。修改图案并交换:
writer.writerow([field.strip() for field in pattern.match(line).groups()])
与:
writer.writerow(pattern.match(line).groups())
将导致缩进保留在它们所属的位置。
我有一个包含一组文件历史记录的列表。我需要将列表中的每个元素分成几列并将其保存到 CSV
文件中。
我需要的列是 commit_id, filename, committer, date, time, line_number, code
。
假设,这是我的清单:
my_list = [
'f5213095324 master/ActiveMasterManager.java (Michael Stack 2010-08-31 23:51:44 +0000 1) /**',
'f5213095324 master/ActiveMasterManager.java (Michael Stack 2010-08-31 23:51:44 +0000 2) *',
'f5213095324 master/ActiveMasterManager.java (Michael Stack 2010-08-31 23:51:44 +0000 3) * Licensed to the Apache Software Foundation (ASF) under one',
'f5213095324 master/ActiveMasterManager.java (Michael Stack 2010-08-31 23:51:44 +0000 4) * or more contributor license agreements.',
...
'b5cf8748198 master/ActiveMasterManager.java (Michael Stack 2012-09-27 05:40:09 +0000 160) if (ZKUtil.checkExists(this.watcher, backupZNode) != -1) {'
]
所需的csv
输出:
commit_id | filename | committer | date | time | line_number | code
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
f5213095324 | master/ActiveMasterManager.java | Michael Stack | 2010-08-31 | 23:51:44 | 1 | /**
f5213095324 | master/ActiveMasterManager.java | Michael Stack | 2010-08-31 | 23:51:44 | 2 | *
f5213095324 | master/ActiveMasterManager.java | Michael Stack | 2010-08-31 | 23:51:44 | 3 | * Licensed to the Apache Software Foundation (ASF) under one
f5213095324 | master/ActiveMasterManager.java | Michael Stack | 2010-08-31 | 23:51:44 | 4 | * or more contributor license agreements.
........
b5cf8748198 | master/ActiveMasterManager.java | Michael Stack | 2012-09-27 | 05:40:09 | 160 | if (ZKUtil.checkExists(this.watcher, backupZNode) != -1) {
我尝试使用此代码:
pattern = re.compile(r'(?P<commit_id>\w+)\s+(?P<filename>[^\s]+)\s+\((?P<committer>.+)\s+(?P<date>\d{4}-\d\d-\d\d)\s+(?P<time>\d\d:\d\d:\d\d).+(?P<line_number>\b\d+\b)\)\s+(?P<code>[^"]*)')
with open('somefile.csv', 'w+', newline='') as f:
writer = csv.writer(f)
writer.writerow(['commit_id', 'filename', 'committer', 'date', 'time', 'line_number', 'code'])
for line in my_list:
writer.writerow([field.strip() for field in pattern.match(line).groups()])
总的来说,代码有效。
但是对于 line number = 160
,它在 line_number
列中写为 -1
,在 code
列中仅写为 {
。
正则表达式中是否缺少某些内容?
我修复了正则表达式。 这应该有效:
pattern = re.compile(r'(?P<commit_id>\w+)\s+(?P<filename>[^\s]+)\s+\((?P<committer>.+)\s+(?P<date>\d{4}-\d\d-\d\d)\s+(?P<time>\d\d:\d\d:\d\d).+?(?P<line_number>\b\d+\b)\)\s+(?P<code>[^"]*)')
我添加了一个问号以使用惰性匹配 ".+" => ".+?"
不完全是您要找的,但这可能很有用。
import re
for row in my_list:
print([x.strip() for x in re.split(r"(?![)])\s+(?![(])", row)])
out:
['f5213095324', 'master/ActiveMasterManager.java', '(Michael', 'Stack', '2010-08-31', '23:51:44', '+0000', '1)', '/**']
['f5213095324', 'master/ActiveMasterManager.java', '(Michael', 'Stack', '2010-08-31', '23:51:44', '+0000', '2)', '*']
...
您的模式的主要问题是 .+
的使用。如果用 .*?
替换它,您不仅可以解决行号问题,还可以解决提交者姓名后的空格问题:
pattern = re.compile(r'(?P<commit_id>\w+)\s+(?P<filename>[^\s]+)\s+\((?P<committer>.*?)\s+(?P<date>\d{4}-\d\d-\d\d)\s+(?P<time>\d\d:\d\d:\d\d).*?(?P<line_number>\b\d+\b)\)\s+(?P<code>[^"]*)')
https://regex101.com/r/f7zjpA/2
编辑:
您没有提到要保留缩进,而且您的代码看起来并不像您真正想要的那样。 Whitespaces/indentations 之前的代码被删除不仅是因为正则表达式模式。有两件事:
在正则表达式模式中,您在
code
组之前使用了\s+
,这排除了所有 whitespaces/indentations。如果你想保留它们,将\s+
替换为\s
,这将只捕获第一个而不是所有的:pattern = re.compile(r'(?P<commit_id>\w+)\s+(?P<filename>[^\s]+)\s+\((?P<committer>.*?)\s+(?P<date>\d{4}-\d\d-\d\d)\s+(?P<time>\d\d:\d\d:\d\d).*?(?P<line_number>\b\d+\b)\)\s(?P<code>[^"]*)')
在 for 循环中,您使用
field.strip()
删除字符串开头和结尾处的所有空格。修改图案并交换:writer.writerow([field.strip() for field in pattern.match(line).groups()])
与:
writer.writerow(pattern.match(line).groups())
将导致缩进保留在它们所属的位置。