Чтение данных из csv-файла и преобразование в правильный тип данных
У меня следующая проблема. Я написал 2-мерный список, где каждый столбец имеет другой тип (bool, str, int, list), в csv-файл. Теперь я хочу снова прочитать данные из csv-файла. Но каждая клетка, которую я читаю, интерпретируется как строка.
Как я могу автоматически преобразовать данные чтения в правильный тип? Или лучше: есть ли возможность сообщить csv-читателю правильный тип данных каждого столбца?
примеры данных (как в csv-файл):
IsActive,Type,Price,States
True,Cellphone,34,"[1, 2]"
,FlatTv,3.5,[2]
False,Screen,100.23,"[5, 1]"
True,Notebook, 50,[1]
4 ответов
как документы объяснить, считыватель CSV не выполняет автоматическое преобразование данных. У вас есть опция QUOTE_NONNUMERIC format, но это приведет только к преобразованию всех полей без кавычек в поплавки. Это очень похоже на поведение других читателей КШМ.
Я не считаю, что csv-модуль Python будет иметь какую-либо помощь в этом случае вообще. Как уже указывали другие,literal_eval()
гораздо лучший выбор.
следующее работает и новообращенные:
- строки
- int
- терки
- списки
- словари
вы также можете использовать его для логических и NoneType, хотя они должны быть отформатированы соответственно для literal_eval()
пройти. LibreOffice Calc отображает логические значения заглавными буквами, когда в Python логические значения капитализируются. Кроме того, вам придется заменить пустые строки на None
(без кавычек)
Я пишу импортер для MongoDB, который делает все это. Ниже приводится часть кода, который я написал до сих пор.
[Примечание: мой csv использует вкладку в качестве разделителя полей. Вы также можете добавить обработку исключений]
def getFieldnames(csvFile):
"""
Read the first row and store values in a tuple
"""
with open(csvFile) as csvfile:
firstRow = csvfile.readlines(1)
fieldnames = tuple(firstRow[0].strip('\n').split("\t"))
return fieldnames
def writeCursor(csvFile, fieldnames):
"""
Convert csv rows into an array of dictionaries
All data types are automatically checked and converted
"""
cursor = [] # Placeholder for the dictionaries/documents
with open(csvFile) as csvFile:
for row in islice(csvFile, 1, None):
values = list(row.strip('\n').split("\t"))
for i, value in enumerate(values):
nValue = ast.literal_eval(value)
values[i] = nValue
cursor.append(dict(zip(fieldnames, values)))
return cursor
вы должны сопоставить строки:
data = """True,foo,1,2.3,baz
False,bar,7,9.8,qux"""
reader = csv.reader(StringIO.StringIO(data), delimiter=",")
parsed = (({'True':True}.get(row[0], False),
row[1],
int(row[2]),
float(row[3]),
row[4])
for row in reader)
for row in parsed:
print row
результаты
(True, 'foo', 1, 2.3, 'baz')
(False, 'bar', 7, 9.8, 'qux')
реквизит для Джона Клементса и кортопи для обучения меня о ast.literal_eval
! Вот что я закончил (Python 2; изменения для 3 должны быть тривиальными):
from ast import literal_eval
from csv import DictReader
import csv
def csv_data(filepath, **col_conversions):
"""Yield rows from the CSV file as dicts, with column headers as the keys.
Values in the CSV rows are converted to Python values when possible,
and are kept as strings otherwise.
Specific conversion functions for columns may be specified via
`col_conversions`: if a column's header is a key in this dict, its
value will be applied as a function to the CSV data. Specify
`ColumnHeader=str` if all values in the column should be interpreted
as unquoted strings, but might be valid Python literals (`True`,
`None`, `1`, etc.).
Example usage:
>>> csv_data(filepath,
... VariousWordsIncludingTrueAndFalse=str,
... NumbersOfVaryingPrecision=float,
... FloatsThatShouldBeRounded=round,
... **{'Column Header With Spaces': arbitrary_function})
"""
def parse_value(key, value):
if key in col_conversions:
return col_conversions[key](value)
try:
# Interpret the string as a Python literal
return literal_eval(value)
except Exception:
# If that doesn't work, assume it's an unquoted string
return value
with open(filepath) as f:
# QUOTE_NONE: don't process quote characters, to avoid the value
# `"2"` becoming the int `2`, rather than the string `'2'`.
for row in DictReader(f, quoting=csv.QUOTE_NONE):
yield {k: parse_value(k, v) for k, v in row.iteritems()}
(Я немного опасаюсь, что я, возможно, пропустил некоторые угловые случаи, связанные с цитированием. Пожалуйста, прокомментируйте, если вы видите какие-либо вопросы!)
альтернатива (хотя это кажется немного экстремальным) вместо использования ast.literal_eval
- Это pyparsing
модуль доступен на PyPi - и посмотреть, если http://pyparsing.wikispaces.com/file/view/parsePythonValue.py образец кода или соотвествующий для чего вы требуете, или может легко быть приспособлен.