Python: чтение csv-файла с произвольным количеством вкладок в качестве разделителя

#python #csv #tabs

#python #csv #вкладки

Вопрос:

Мой csv-файл отформатирован так, что все столбцы выровнены с помощью одной или нескольких вкладок между разными значениями.

Я знаю, что можно использовать одну вкладку в качестве разделителя с csv.register_dialect("tab_delimiter", delimiter="t") . Но это работает только с одной табуляцией между значениями. Я хотел бы обработать файл, сохранив его формат, т. Е. не удаляя дублирующиеся вкладки. Каждое поле (строка, столбец) содержит значение.

Возможно ли использовать количество вкладок 1 в качестве разделителя или игнорировать дополнительные вкладки, не влияя на нумерацию значений в строке? row[1] должно быть вторым значением, не зависящим от того, сколько вкладок находится между ними row[0] .

Комментарии:

1. Читая документы, я понял, что вы можете использовать только один символ в качестве разделителя. Я думаю, ваш лучший вариант — предварительно обработать файл, чтобы удалить дублирующиеся вкладки.

2. При условии, что каждая строка содержит данные для каждого столбца, просто с различным количеством вкладок в качестве разделителей, вы можете просто обработать это с пониманием списка, separated = [item for item in row if item] где row находится строка в вашем csv.reader() . Если в некоторых строках есть пустые записи, то я не вижу никакого способа добиться этого.

Ответ №1:

 ##Sample.txt
##ID    name    Age
##1 11  111
##2     22  222


import pandas as pd
df=pd.read_csv('Sample.txt' ,sep=r't ')
print df
  

Комментарии:

1. Есть ли способ заставить это работать с csv вместо pandas ?

Ответ №2:

Предполагая, что пустых полей никогда не будет, вы можете использовать генератор для удаления дубликатов из входящего CSV-файла, а затем использовать csv модуль как обычно:

 import csv

def de_dup(f, delimiter='t'):
    for line in f:
        yield delimiter.join(field for field in line.split(delimiter) if field)

with open('data.csv') as f:
    for row in csv.reader(de_dup(f), delimiter='t'):
        print(row)
  

Альтернативный способ — использовать re.sub() в генераторе:

 import re

def de_dup(f, delimiter='t'):
    for line in f:
        yield re.sub(r'{}{{2,}}'.format(delimiter), delimiter, line)
  

но это все еще имеет ограничение, заключающееся в том, что все поля должны содержать значение.

Ответ №3:

Для меня наиболее удобным способом работы с несколькими вкладками было использование дополнительной функции, которая принимает строку и удаляет пустые значения / поля, созданные несколькими вкладками подряд. Это не влияет на форматирование csv-файла, и я могу получить доступ ко второму значению в строке с помощью row[1] — даже с несколькими вкладками перед ним.

 def remove_empty(line):
    result = []
    for i in range(len(line)):
        if line[i] != "":
            result.append(line[i])
    return result
  

И в коде, где я читаю файл и обрабатываю значения:

 for row in reader:
    row = remove_empty(row)
    **continue processing normally**
  

Я думаю, что это решение похоже на решение mhawke, но с его решением я не мог получить доступ к тем же значениям с row[i] , что и раньше (т. Е. только с одним разделителем между каждым значением).

Ответ №4:

Или полностью общим решением для любого типа повторяющихся разделителей является рекурсивная замена каждого множественного разделителя одним разделителем и запись в новый файл (хотя это медленно для файлов CSV размером в гигабайт):

 def replaceMultipleSeparators( fileName, oldSeparator, newSeparator ):
  linesOfCsvInputFile = open( fileName, encoding='utf-8', mode='r' ).readlines()

  csvNewFileName = fileName   ".new"
  print('Writing:   %s replacing %s with %s' % ( csvNewFileName, oldSeparator, newSeparator ) , end='' )
  outputFileStream = open( newFileName, 'w' )
  for line in linesOfCsvInputFile:
    newLine = line.rstrip()
    processedLine = ""
    while newLine != processedLine:
      processedLine = newLine
      newLine = processedLine.replace( oldSeparator   oldSeparator, oldSeparator )
    newLine = newLine.replace( oldSeparator, newSeparator )
    outputFileStream.write( newLine   'n' )
  outputFileStream.close()
  

при заданном вводе testFile.csv будет генерироваться testFile.csv.new с вкладками, замененными каналами, если вы запустите:

 replaceMultipleSeparators( 'testFile.csv', 't', '|' )
  

Иногда вам потребуется заменить кодировку ‘utf-8’ на ‘latin-1’ для некоторых CSV-файлов, созданных Microsoft US. Смотрите ошибки, связанные с чтением 0xe4 для этой проблемы.