Я пытаюсь разобрать файл CSV в Python; элементы в файле увеличиваются после первой строки с 6 до 7.
Пример CSV:
Title,Name,Job,Email,Address,ID
Eng.,"FirstName, LastName",Engineer,[email protected],ACME Company,1234567
Eng.,"FirstName, LastName",Engineer,[email protected],ACME Company,1234567
Мне нужен способ форматирования и представления вывода в виде чистой таблицы.
Насколько я понимаю, проблема с моим кодом заключается в том, что, начиная со второй строки, элементы CSV увеличиваются с 6 до 7. Таким образом, он выдает следующую ошибку.
print(stringFormat.format(item.split(',')[0], item.split(',')[1], item.split(',')[2],
item.split(',')[3], item.split(',')[4], item.split(',')[5],))
IndexError: list index out of range
Мой код:
stringFormat = "{:>10} {:>10} {:>10} {:>10} {:>10} {:>10}"
with open("the_file", 'r') as file:
for item in file.readlines():
print(stringFormat.format(item.split(',')[0], item.split(',')[1],
item.split(',')[2], item.split(',')[3],
item.split(',')[4], item.split(',')[5],
item.split(',')[6]))
@PranavHosangadi, спасибо за ответ, но я не хочу использовать какую-либо библиотеку. Мой код работает, за исключением того, что после первой строки я получаю ошибку из-за увеличенного элемента (ID). Попробуйте код. И вы увидите, что я имею в виду.
@Al1nuX: то, что ошибки не было, не означает, что ваш код работал правильно.
Если кто-то попытается запустить код, поймет, в чем проблема. Код может работать только с фиксированным числом индексов. Как только индекс увеличится, он выдаст ошибку. Мне нужно решение, которое можно настроить с изменением index.
Интересно, кто минусовал? по крайней мере, попытайтесь внести свой вклад или перестаньте отрицать вопросы других людей. Что не так ясно, бесполезно или без усилий в вопросе?
Я не понизил голосование, но думаю, что причина, по которой кто-то это сделал, заключалась в том, что вы неправильно поняли проблему (или полностью искусственное ограничение неиспользования внешних библиотек).
@martineau, и именно поэтому я прошу помощи в первую очередь.
Вы можете попробовать что-то вроде этого. Цикл for использует длину разделенного элемента, поэтому вы можете иметь строки переменной длины.
stringFormats = ["{:>10}", "{:>10}", "{:>10}", "{:>10}", "{:>10}", "{:>10}", "{:>10}"]
with open("the_file", 'r') as file:
for item in file.readlines():
s_item = item.split(',')
f_item = ''
for x in range(len(s_item)):
f_item += stringFormats[x].format(s_item[x])
print(f_item)
Конечно, вам нужно как минимум достаточно строковых форматов, чтобы соответствовать наибольшей длине строки. Если вам никогда не нужно использовать другую опцию, вы можете просто изменить stringFormat обратно на одну строку вместо того, чтобы перебирать ее.
stringFormat = "{:>10}"
with open("the_file", 'r') as file:
for item in file.readlines():
s_item = item.split(',')
f_item = ''
for a_field in s_item:
f_item += stringFormat.format(a_field)
print(f_item)
Спасибо за ответ. Ваш код работает! Однако я не понимаю, что означают s_item и f_item. Кроме того, между отображаемыми элементами нет линий; как я могу указать и настроить пробелы между ними? И последнее, как я могу удалить " " из "Имя, Фамилия" в выводе?
Вы можете сделать это с помощью очень простых циклов for, как показано ниже. Я добавил оператор печати, чтобы показать эффекты
# 'r' is not needed, it is the default value if omitted
with open("file_name") as infile:
result = []
# split the read() into a list of lines
# I prefer this over readlines() as this removes the EOL character
# automagically (I mean the `\n` char)
for line in infile.read().splitlines():
# check if line is empty (stripping all spaces)
if len(line.strip()) == 0:
continue
# another way would be to check for ',' characters
if ',' not in line:
continue
# set some helper variables
line_result = []
found_quote = False
element = ""
# iterate over the line by character
for c in line:
# toggle the found_quote if quote found
if c == '"':
found_quote = not found_quote
continue
if c == ",":
if found_quote:
element += c
else:
# append the element to the line_result and reset element
line_result.append(element)
element = ""
else:
# append c to the element
element += c
# append leftover element to the line_result
line_result.append(element)
# append the line_result to the final result
result.append(line_result)
print(len(line_result), line_result)
print('------------------------------------------------------------')
stringFormat = "{:>10} {:>20} {:>20} {:>20} {:>20} {:>10}"
for line in result:
print(stringFormat.format(*line))
выход
6 ['Title', 'Name', 'Job', 'Email', 'Address', 'ID']
6 ['Eng.', 'FirstName, LastName', 'Engineer', '[email protected]', 'ACME Company', '1234567']
6 ['Eng.', 'FirstName, LastName', 'Engineer', '[email protected]', 'ACME Company', '1234567']
------------------------------------------------------------
Title Name Job Email Address ID
Eng. FirstName, LastName Engineer [email protected] ACME Company 1234567
Eng. FirstName, LastName Engineer [email protected] ACME Company 1234567
Примечания о сортировке списка списков. Он будет сравнивать первый элемент внутренних списков друг с другом. Если они совпадают, он будет сравнивать второй элемент внутренних списков друг с другом и т. д. Из-за этого вы можете захотеть переместить столбец идентификатора во второй столбец в результирующем списке, так как это, кажется, то, что называется уникальным идентификатор (UID).
with open("file_name") as infile:
lines = infile.read().splitlines()
# set the header and remove it from lines.
header = lines.pop(0).split(',')
# rearrange the header to put the last element (date) first
# -1 gets the last element (eg, count from end)
header.insert(0, header.pop(-1))
# store the header length as this will speed up the process for longer files
# otherwise you would have to call len(header) in each iteration of the loop
header_len = len(header)
result = []
for line in lines:
if ',' not in line:
continue
# split the line once here, so we don't have to split it a million
# times in the rest of the loop
split_line = line.split(',')
if len(split_line) > header_len:
# note, you can remove the strip('"') if you want to keep the quotation marks
# also note that .pop() removes the element "in place", which is why I
# use .pop(1) twice. first time it gets firstname, second time it gets lastname
split_line.insert(1, f"{split_line.pop(1)},{split_line.pop(1)}".strip('"'))
# move the date element to the start
split_line.insert(0, split_line.pop(-1))
# do some slicing on the date element to turn it into YYYYMMDD as this allows for
# proper sorting without any hassle. I'm assuming the date you provided is in the format
# MM/DD/YYYY. You can easily move the order around if it's DD/MM/YYYY
# Also, pad day/month with leading zero's using f"{string:>02}"
split_line[0] = f"{split_line[0].split('/')[2]}{split_line[0].split('/')[0]:>02}{split_line[0].split('/')[1]:>02}"
result.append(split_line)
# sort it. Since the date is in numeric format, and the first element, it sorts
# properly automagically
result.sort()
# if you want you can re-format the date again. you can do so with some list slicing
# since the date string is now properly formatted this is very easy to do
# because the sort() above happens outside the initial loop, we cannot do it inside said loop
for line in result:
line[0] = f"{line[0][6:]}/{line[0][4:6]}/{line[0][0:4]}"
# insert the header
result.insert(0, header)
stringFormat = "{:>10} {:>25} {:>20} {:>20} {:>20} {:>10} {:>10}"
for line in result:
print(stringFormat.format(*line))
# write it as a CSV file with ; used as separator instead
with open("output.csv", "w") as outfile:
for line in result:
outfile.write(";".join(line) + "\n")
Тоже отличное решение. действительно полезно. Можете ли вы отредактировать код, чтобы включить ( с оператором open («file_name», 'r') as file: ), пожалуйста?
готово, обратите внимание, что 'r'
не требуется при открытии файлов для чтения...
Я бы проголосовал 2 раза, если бы мог! спасибо, брат, это поможет мне больше узнать о чтении файлов и управлении ими. Однако в конце я получаю сообщение об ошибке: print(stringFormat.format(*line)) IndexError: индекс замены 1 вне диапазона для кортежа позиционных аргументов
Я думаю, что у вас могут быть пустые строки во входном файле, я добавил два примера проверки работоспособности непосредственно под первым циклом for. Также обратите внимание, что вы можете принять ответ вместо голосования :-)
Если последний столбец справа — это таблица дат, то можно ли ее вывести влево и сделать первой таблицей, отсортировав даты по порядку сверху вниз? и записать в файл?
Да всему этому. Нарезка списка - ваш друг, чтобы изменить порядок и дату. Для сортировки это немного зависит от того, как на самом деле отформатирована дата. Вы всегда можете просто импортировать дату и время и преобразовать ее в объект даты и времени, что упрощает обработку. Можете ли вы предоставить образец фактической строки для даты?
Давайте продолжить обсуждение в чате.
Я получаю эту ошибку «print (stringFormat.format (* line)) IndexError: индекс замены 6 вне диапазона для кортежа позиционных аргументов»
вы изменили stringFormat? Я добавил один элемент по мере добавления столбца даты. Если нет, попробуйте распечатать строку для отладки, чтобы увидеть, соответствует ли строка, выдающая ошибку, тому, что вы ожидаете.
Я удалил один из "{:> 10}", теперь он работает.
Когда вы видите кавычки в файле csv, это означает, что все, заключенное в кавычки, является одно поле, даже если оно может содержать запятую внутри кавычек. Таким образом, ваши строки имеют только 6 столбцов, как и ваш заголовок. Библиотека
csv
является частью стандартной библиотеки Python (это не внешняя библиотека). Используйте это, он обрабатывает правильный анализ файлов csv, включая кавычки. Если вам не разрешено даже использовать это, вам придется подумать о том, как избежать разделения строки на запятую, заключенную в кавычки.