我有一个.txt文件(从网站上抓取为预格式化文本),其中的数据如下所示:
B, NICKOLAS CT144531X D1026 JUDGE ANNIE WHITE JOHNSON
ANDREWS VS BALL JA-15-0050 D0015 JUDGE EDWARD A ROBERTS
我想删除列之间所有多余的空格(它们实际上是不同数量的空格,而不是制表符)。然后我还想用一些分隔符(制表符或管道,因为数据中有逗号)来代替它,就像这样:
ANDREWS VS BALL|JA-15-0050|D0015|JUDGE EDWARD A ROBERTS
环顾四周,发现最好的选择是使用regex或shlex进行拆分。两个类似的场景:
- Python正则表达式必须去掉引号之间的空白
- 从dict:Python中删除空白
您可以将正则表达式's{2,}'
(两个或多个空白字符)应用于每一行,并用单个'|'
字符替换匹配项。
>>> import re
>>> line = 'ANDREWS VS BALL JA-15-0050 D0015 JUDGE EDWARD A ROBERTS '
>>> re.sub('s{2,}', '|', line.strip())
'ANDREWS VS BALL|JA-15-0050|D0015|JUDGE EDWARD A ROBERTS'
在应用re.sub
之前,从该行中去除任何前导和尾随空格可以确保不会在该行的开头和结尾处获得'|'
字符。
你的实际代码应该看起来像这样:
import re
with open(filename) as f:
for line in f:
subbed = re.sub('s{2,}', '|', line.strip())
# do something here
这个怎么样?
your_string ='ANDREWS VS BALL JA-15-0050 D0015 JUDGE EDWARD A ROBERTS'
print re.sub(r's{2,}','|',your_string.strip())
输出:
ANDREWS VS BALL|JA-15-0050|D0015|JUDGE EDWARD A ROBERTS
扩展:
我使用了re.sub()
,它包含3个参数、一个模式、一个要替换的字符串和一个要处理的字符串
我所做的是将至少两个空间放在一起,我用|
替换了它们,并将其应用于字符串。
s = """B, NICKOLAS CT144531X D1026 JUDGE ANNIE WHITE JOHNSON
ANDREWS VS BALL JA-15-0050 D0015 JUDGE EDWARD A ROBERTS
"""
# Update
re.sub(r"(S) {2,}(S)(n?)", r"1|23", s)
In [71]: print re.sub(r"(S) {2,}(S)(n?)", r"1|23", s)
B, NICKOLAS|CT144531X|D1026|JUDGE ANNIE WHITE JOHNSON
ANDREWS VS BALL|JA-15-0050|D0015|JUDGE EDWARD A ROBERTS
考虑到至少有两个空格分隔列,可以使用以下内容:
lines = [
'B, NICKOLAS CT144531X D1026 JUDGE ANNIE WHITE JOHNSON ',
'ANDREWS VS BALL JA-15-0050 D0015 JUDGE EDWARD A ROBERTS '
]
for line in lines:
parts = []
for part in line.split(' '):
part = part.strip()
if part: # checking if stripped part is a non-empty string
parts.append(part)
print('|'.join(parts))
输入输出:
B, NICKOLAS|CT144531X|D1026|JUDGE ANNIE WHITE JOHNSON
ANDREWS VS BALL|JA-15-0050|D0015|JUDGE EDWARD A ROBERTS
看起来您的数据是"文本表"格式的。
我建议使用第一行来计算每列的起点和长度(手动或用regex编写脚本来确定可能的列),然后编写脚本来迭代文件的行,将行分割为列段,并对每个段应用strip。
如果使用正则表达式,则必须跟踪列数,并且如果任何给定行的列数超过预期数(或与其他行的数不同),则会引发错误。如果列的值有两个或多个空格,则拆分两个或更多个空格将中断,这不仅是完全可能的,而且也是可能的像这样的文本表并不是为了在正则表达式上拆分而设计的,而是为了在列索引位置上拆分
在保存数据方面,您可以使用csv模块写入/读取csv文件。这将使您能够更好地处理引用和转义字符,而不是指定分隔符。如果其中一列的值为|
字符,除非您使用处理转义或带引号的文字的策略对数据进行编码,否则您的输出将在读取时中断。
解析上面的文本看起来是这样的(我用括号嵌套了一个列表理解,而不是传统的格式,这样更容易理解):
cols = ((0,34),
(34, 50),
(50, 59),
(59, None),
)
for line in lines:
cleaned = [i.strip() for i in [line[s:e] for (s, e) in cols]]
print cleaned
然后你可以用这样的东西来写
import csv
with open('output.csv', 'wb') as csvfile:
spamwriter = csv.writer(csvfile, delimiter='|',
quotechar='"', quoting=csv.QUOTE_MINIMAL)
for line in lines:
spamwriter.writerow([line[col_start:col_end].strip()
for (col_start, col_end) in cols
])
看起来这个库可以很好地解决这个问题:http://docs.astropy.org/en/stable/io/ascii/fixed_width_gallery.html#fixed-宽度通道
令人印象深刻。。。