#python #csv #utf-8
Вопрос:
Я провел 5 часов в темных закоулках SO, поэтому я публикую этот вопрос в качестве последнего средства, и я искренне надеюсь, что кто-нибудь сможет указать мне правильное направление здесь:
Сценарий:
- У меня есть некоторые CSV-файлы (CSV-файлы UTF-8: проверяются командой file-I) из опросов Google, которые представлены на нескольких языках . Выход:
download.csv: application/csv; charset=utf-8
- У меня есть файл «словарь», в котором есть переводы вопросов и ответов (один столбец-это язык$, а другой-английский).
- В данных Google есть МНОГО символов специального типа (умлауты, буквы с французским акцентом и т. Д.), Потому что французский, немецкий, голландский
- Файл словаря, который я создал, отлично читается как UTF-8, включая специальные символы, и точно создает ключи поиска/замены (проверено с помощью команд печати).
Проблема в том, что файлы Google читаются правильно (поддерживают правильные символы) только с помощью функции csv.read в Python. Однако у этой функции нет .replace, и поэтому я могу сделать то или другое:
- прочитайте исходный файл, не делайте никаких замен и получите идеальную копию (не то, что мне нужно).
- преобразуйте csv-файлы/строки в файловый ввод/строку (все еще UTF-8, имейте в виду) и получите полностью разбитый выходной файл с отсутствующими заменами, потому что данные каким-то образом «теряют» кодировку между чтением csv и строкой?
Код (здесь) наиболее близок к работе, за исключением того, что в csv .reader нет метода.replace:
import csv
#set source, output
source = 'fr_to_trans.csv'
output = 'fr_translated.csv'
dictionary = 'frtrans.csv'
find = []
replace = []
# build the dictionary itself:
with open(dictionary, encoding='utf-8') as dict_file:
for line in dict_file:
#print(line)
temp_split = []
temp_split = line.split(',')
if "!!" in temp_split[0] :
temp_split[0] = temp_split[0].replace("!!", ",")
find.append(temp_split[0])
if "!!" in temp_split[1] :
temp_split[1] = temp_split[1].replace("!!", ",")
replace.append(temp_split [1])
#print(len(find))
#print(len(replace))
#set loop counters
check_each = len(find)
# Read in the file to parse
with open(source, 'r', encoding='utf-8') as s_file, open(output, 'w', encoding='utf-8') as t_file :
output_writer = csv.writer(t_file)
for row in csv.reader(s_file):
the_row = row
print(the_row) #THIS RETURNS THE CORRECT, FORMATTED, UTF-8 DATA
i = 0
# find and replace everything in the find array with it's value in the replace array
while i < check_each :
print(find[i])
print(replace[i])
# THIS LINE DOES NOT WORK:
the_row = the_row.replace(find[i], replace[i])
i = i 1
output_writer.writerow(the_row)
Я должен предположить, что, хотя в файлах Google указано, что они UTF-8, они являются специальными «UTF-8 под брендом Google» или какой-то подобной ерундой. Тот факт, что файл правильно открывается с помощью csv.reader, но затем вы ничего не можете с ним сделать, бесит сверх всякой меры.
Просто чтобы уточнить, что я пытался:
- Обрабатывайте файлы как текст и позволяйте Python сортировать кодировку (не удается)
- Обрабатывайте файлы как текст UTF-8 (сбой)
- Откройте файл как UTF-8, замените строки и запишите с помощью csv.writer (сбой)
- Преобразуйте the_row в строку, затем замените, затем запишите с помощью csv.writer (не удается)
- Быстрое редактирование — попробовал utf-8-sig со строками — лучше, но вывод все равно полностью искажен, потому что он читает его не как csv, а как строки
Я еще не пробовал:
- сравнение «ячейка за ячейкой» вместо всей строки (работаем над этим, пока это происходит)
- Другая кодировка файла (я могу получить только CSV UTF-8, поэтому потребуется какая-то утилита?)
Если бы это был текст ASCII, я бы сделал это давным-давно, но вся эта «UTF-8, которой нет, но есть» сводит меня с ума. У кого — нибудь есть какие-нибудь идеи на этот счет?
Комментарии:
1. Там нет такого понятия, как «специальный Google фирменный UTF-8», вам придется быть более конкретным, чем это.
2. «Обрабатывайте файлы как текст, и пусть Python разберется с кодировкой (сбой)» . Такого понятия, как «обнаружение кодировки волшебного текстового файла», также не существует. Python не может разобраться в этом для вас. Либо кодировка четко объявлена, будь то через HTTP-заголовки или через знак порядка байтов, либо вам необходимо знать ее перед открытием текстового файла.
3. Возможно, вам захочется добавить соответствующие образцы ваших файлов, которые а) отображают структуру файла и б) воспроизводимо демонстрируют проблему. В целом, это не так сложно, как кажется в вашем вопросе, но вы перепутали несколько концепций.
4. Я хотел бы, чтобы я мог, но они содержат много информации о PII/бренде/частной информации, и я не могу поделиться файлами исходных данных. Я думаю, что самая большая проблема заключается в том, что в отличие от большинства упражнений по поиску/замене, я хочу эффективно заменять целые ячейки листа, например, сопоставляя полную фразу на французском языке, а затем заменяя каждое ее вхождение переводом на английский. Проблема возникает, когда кодировка файла для специальных символов не сохраняется, и не удается выполнить сопоставление/вывод поврежден специальными символами. Суть в том, почему чтение файла в формате UTF-8 по сравнению с собственным CSV отличается.
5. Публикуйте поддельные данные в том же формате. Нам не нужно много линий.
Ответ №1:
Каждая строка, полученная с помощью csv.reader
, представляет собой список значений ячеек, таких как
['42', 'spam', 'eggs']
Таким образом, линия
# THIS LINE DOES NOT WORK:
the_row = the_row.replace(find[i], replace[i])
не может работать, потому что в списках нет метода замены.
Что может сработать, так это перебрать список строк и найти/заменить значение каждой ячейки (я предполагаю, что все они являются строками).
the_row = [cell.replace(find[i], replace[i]) for cell in the row]
Однако, если все, что вы хотите сделать, это заменить все экземпляры некоторых символов в файле на некоторые другие символы, то проще открыть файл в виде текстового файла и заменить его без вызова каких-либо механизмов csv:
with open(source, 'r', encoding='utf-8') as s_file, open(output, 'w', encoding='utf-8') as t_file :
text = source.read()
for old, new in zip(find, replace):
text = text.replace(old, new)
t_file.write(text)
Если сопоставление поиска/замены одинаково для всех файлов, вы можете использовать str.translate, чтобы избежать цикла for.
# Make a reusable translation table
trans_table = str.maketrans(dict(zip(find, replace)))
with open(source, 'r', encoding='utf-8') as s_file, open(output, 'w', encoding='utf-8') as t_file :
text = source.read()
text = text.translate(trans_table)
t_file.write(text)
Для ясности: CSV-это текстовые файлы, отформатированные только так, чтобы их содержимое можно было интерпретировать как строки и столбцы. Если вы хотите манипулировать их содержимым как чистым текстом, вы можете редактировать их как обычные текстовые файлы: до тех пор, пока вы не измените какие-либо символы, используемые в качестве разделителей или кавычек, они все равно будут использоваться в качестве CSV, когда вы захотите использовать их как таковые.
Комментарии:
1. Я надеялся, что вы вмешаетесь, ваш ответ на другом посте также привел меня к utf-sig. Я попробовал ячейку.заменить, и это вроде как работает, но помещает каждую букву переведенного значения в свою собственную колонку. Метод trans_table не работает со значениями в разделе найти и заменить, потому что я еще не понимаю, как его использовать (все еще исследую), но это может быть так. Проблема в том, что я сопоставляю целые фразы на других языках, которые должны совпадать с полной фразой, чтобы заменить полную фразу. Они не находятся в одном и том же поле каждый раз или всегда в одном и том же порядке.