Python 如何使用csv嗅探器检测双字符/连续字符作为分隔符?
例如,下表使用双空格作为表值的分隔符,但在标题行中的开口圆括号之前使用单空格。当csv.Sniffer应用于文件时,将返回单个空格作为分隔符,而不是预期的双空格。如何获得双空格作为结果分隔符 日ddd N d E d X m Y Z c S p 277 40.52 -36.59 0.11 -0.50 -1.62 30.17 277 40.52 -36.49 0.18 -0.04 -1.66 30.14 277 40.51 -36.39 0.14 -0.07 -1.64 30.15Python 如何使用csv嗅探器检测双字符/连续字符作为分隔符?,python,csv,whitespace,separator,sniffer,Python,Csv,Whitespace,Separator,Sniffer,例如,下表使用双空格作为表值的分隔符,但在标题行中的开口圆括号之前使用单空格。当csv.Sniffer应用于文件时,将返回单个空格作为分隔符,而不是预期的双空格。如何获得双空格作为结果分隔符 日ddd N d E d X m Y Z c S p 277 40.52 -36.59 0.11 -0.50 -1.62 30.17 277 40.52 -36.49 0.18 -0.04 -1.66 30.14 277 40.51 -36.39 0.14 -0.07 -1
这本质上是欺骗-如果您认为可能以“”作为分隔符,请重写它们:
with open("example.csv","w") as f:
f.write("""Day (ddd) N (d) E (d) X (m) Y(s) Z (c) S (p)
277 40.52 -36.59 0.11 -0.50 -1.62 30.17
277 40.52 -36.49 0.18 -0.04 -1.66 30.14
277 40.51 -36.39 0.14 -0.07 -1.64 30.15""")
import csv
import io
import re
# keeps the whole file in memory - for big files >2G you'll need to rewrite
# to linebased parsing
stringIO = io.StringIO()
with open('example.csv') as csvfile:
for line in csvfile:
stringIO.write(re.sub(" ","|",line))
stringIO.seek(0)
sn = csv.Sniffer()
dialect = sn.sniff(stringIO.read(1024))
# back to start
stringIO.seek(0)
reader = csv.reader(stringIO, dialect)
for line in reader:
print(line)
输出:
['Day (ddd)', 'N (d)', 'E (d)', 'X (m)', 'Y(s)', 'Z (c)', 'S (p)']
['277', '40.52', '-36.59', '0.11', '-0.50', '-1.62', '30.17']
['277', '40.52', '-36.49', '0.18', '-0.04', '-1.66', '30.14']
['277', '40.51', '-36.39', '0.14', '-0.07', '-1.64', '30.15']
如果文件不包含嗅探器,则嗅探器可用于普通分隔符,如果包含嗅探器,则会将其替换为“|”,希望您的文件中尚未使用“|”,您可能需要检查它并使用“;,”等。如果使用,则改为使用。这本质上是欺骗-如果您认为可能使用“”作为分隔符,请重写它们:
with open("example.csv","w") as f:
f.write("""Day (ddd) N (d) E (d) X (m) Y(s) Z (c) S (p)
277 40.52 -36.59 0.11 -0.50 -1.62 30.17
277 40.52 -36.49 0.18 -0.04 -1.66 30.14
277 40.51 -36.39 0.14 -0.07 -1.64 30.15""")
import csv
import io
import re
# keeps the whole file in memory - for big files >2G you'll need to rewrite
# to linebased parsing
stringIO = io.StringIO()
with open('example.csv') as csvfile:
for line in csvfile:
stringIO.write(re.sub(" ","|",line))
stringIO.seek(0)
sn = csv.Sniffer()
dialect = sn.sniff(stringIO.read(1024))
# back to start
stringIO.seek(0)
reader = csv.reader(stringIO, dialect)
for line in reader:
print(line)
输出:
['Day (ddd)', 'N (d)', 'E (d)', 'X (m)', 'Y(s)', 'Z (c)', 'S (p)']
['277', '40.52', '-36.59', '0.11', '-0.50', '-1.62', '30.17']
['277', '40.52', '-36.49', '0.18', '-0.04', '-1.66', '30.14']
['277', '40.51', '-36.39', '0.14', '-0.07', '-1.64', '30.15']
如果文件不包含嗅探器,则嗅探器可用于普通分隔符,如果包含嗅探器,则会将其替换为“|”,希望您的文件中尚未使用“|”,您可能需要检查它并使用“;,”如我在评论中所说,csv模块通常不支持多字符分隔符。但是,在这种特殊情况下,有一种解决方法,因为分隔符恰好是一个空白字符
import csv
filename = "double_whitespace.csv"
with open(filename, 'r', newline='') as file:
reader = csv.reader(file, delimiter=' ', skipinitialspace=True)
next(reader) # Skip header row.
for row in reader:
print(row)
输出:
['Day (ddd)', 'N (d)', 'E (d)', 'X (m)', 'Y(s)', 'Z (c)', 'S (p)']
['277', '40.52', '-36.59', '0.11', '-0.50', '-1.62', '30.17']
['277', '40.52', '-36.49', '0.18', '-0.04', '-1.66', '30.14']
['277', '40.51', '-36.39', '0.14', '-0.07', '-1.64', '30.15']
['277', '40.52', '-36.59', '0.11', '-0.50', '-1.62', '30.17']
['277', '40.52', '-36.49', '0.18', '-0.04', '-1.66', '30.14']
['277', '40.51', '-36.39', '0.14', '-0.07', '-1.64', '30.15']
正如我在评论中所说,csv模块通常不支持多字符分隔符。但是,在这种特殊情况下,有一种解决方法,因为分隔符恰好是一个空白字符
import csv
filename = "double_whitespace.csv"
with open(filename, 'r', newline='') as file:
reader = csv.reader(file, delimiter=' ', skipinitialspace=True)
next(reader) # Skip header row.
for row in reader:
print(row)
输出:
['Day (ddd)', 'N (d)', 'E (d)', 'X (m)', 'Y(s)', 'Z (c)', 'S (p)']
['277', '40.52', '-36.59', '0.11', '-0.50', '-1.62', '30.17']
['277', '40.52', '-36.49', '0.18', '-0.04', '-1.66', '30.14']
['277', '40.51', '-36.39', '0.14', '-0.07', '-1.64', '30.15']
['277', '40.52', '-36.59', '0.11', '-0.50', '-1.62', '30.17']
['277', '40.52', '-36.49', '0.18', '-0.04', '-1.66', '30.14']
['277', '40.51', '-36.39', '0.14', '-0.07', '-1.64', '30.15']
下面是另一个解决方案,它使用了这样一个事实:传递给它的第一个参数必须是类似文件的。这意味着您可以提供自定义类的实例,该实例将文件行中的双空格字符更改为其他单个字符,如逗号。如果这样做,则可以像处理其他行一样处理标题行 以下是我的建议:
import csv
class CSV_Translater:
""" File-like object that translates characters. """
def __init__(self, f, old, new):
self.f, self.old, self.new = f, old, new
def __iter__(self):
return self
def __next__(self):
return next(self.f).replace(self.old, self.new)
if __name__ == '__main__':
DELIMITER = ','
filename = "double_whitespace.csv"
with open(filename, 'r', newline='') as file:
translator = CSV_Translater(file, ' ', DELIMITER)
for row in csv.reader(translator, delimiter=DELIMITER):
print(row)
输出
['daydddd','ndd','eded','xm','Ys','zc','sps']
['277', '40.52', '-36.59', '0.11', '-0.50', '-1.62', '30.17']
['277', '40.52', '-36.49', '0.18', '-0.04', '-1.66', '30.14']
['277', '40.51', '-36.39', '0.14', '-0.07', '-1.64', '30.15']
下面是另一个解决方案,它使用了这样一个事实:传递给它的第一个参数必须是类似文件的。这意味着您可以提供自定义类的实例,该实例将文件行中的双空格字符更改为其他单个字符,如逗号。如果这样做,则可以像处理其他行一样处理标题行 以下是我的建议:
import csv
class CSV_Translater:
""" File-like object that translates characters. """
def __init__(self, f, old, new):
self.f, self.old, self.new = f, old, new
def __iter__(self):
return self
def __next__(self):
return next(self.f).replace(self.old, self.new)
if __name__ == '__main__':
DELIMITER = ','
filename = "double_whitespace.csv"
with open(filename, 'r', newline='') as file:
translator = CSV_Translater(file, ' ', DELIMITER)
for row in csv.reader(translator, delimiter=DELIMITER):
print(row)
输出
['daydddd','ndd','eded','xm','Ys','zc','sps']
['277', '40.52', '-36.59', '0.11', '-0.50', '-1.62', '30.17']
['277', '40.52', '-36.49', '0.18', '-0.04', '-1.66', '30.14']
['277', '40.51', '-36.39', '0.14', '-0.07', '-1.64', '30.15']
你真的需要闻一下吗?怀疑它的可能性…这个问题很容易可视化,尽管可能没有在csv.Sniffer中实现。不一定使用嗅探器,如何将双空格作为分隔符而不是单个空格?csv模块不支持多字符分隔符。谢谢Patrick Artner和martineau。对于获取正确分隔符的问题,还有其他解决方案吗?如果您确实知道它是这种格式,并且可以将文件保存在内存中,则可以将data=re.subr,|,file.read将其存储在StringIO中,并使用csv.readeriostring,delimiter=|来处理它。您真的需要嗅探它吗?怀疑它的可能性…这个问题很容易可视化,尽管可能没有在csv.Sniffer中实现。不一定使用嗅探器,如何将双空格作为分隔符而不是单个空格?csv模块不支持多字符分隔符。谢谢Patrick Artner和martineau。对于获取正确分隔符的问题,还有其他解决方案吗?如果您确实知道它是这种格式,并且可以将文件保存在内存中,则可以将data=re.subr,|,file.read将其存储在StringIO中,并使用csv.readeriostring,delimiter=|来处理它。@PatrickArtner:True,但是它可以被处理,并且只有一个标题…也许通过在那一行上执行re.sub或更简单的str.replace。谢谢。标题行应该保留,否则,只有一个分隔符。布伦纳:请看我刚才发布的另一个答案。@PatrickArtner:是的,但它可以是b
e处理,并且只有一个标题…可能通过在这一行上执行re.sub或更简单的str.replace。谢谢。标题行应该保留,否则,只有一个分隔符。布伦纳:请看我刚才发布的另一个答案。谢谢。在记忆中作弊的解决方案是有希望的。我得试试。在此之前,在替换它之前,还应该可以检测双空格作为分隔符。谢谢。在记忆中作弊的解决方案是有希望的。我得试试。在此之前,在替换它之前,还可以检测双空格作为分隔符。谢谢martineau。将文件封装到对象中的想法可能会让我更好地控制它。我仍然需要首先检测双空格,但是检测分隔符的问题似乎已经解决了。你必须自己检测它-因为正如我所说,csv模块不支持多字符分隔符,所以csv.Sniffer永远不会检测到它们,因为它们在技术上不是csv文件。您可以查看,也许可以创建一个处理它们的自定义版本。谢谢martineau。将文件封装到对象中的想法可能会让我更好地控制它。我仍然需要首先检测双空格,但是检测分隔符的问题似乎已经解决了。你必须自己检测它-因为正如我所说,csv模块不支持多字符分隔符,所以csv.Sniffer永远不会检测到它们,因为它们在技术上不是csv文件。您可以查看,或许可以创建一个自定义版本来处理它们。