Python 3.8.5 альтернатива .заменить на csv.reader и кодировки тайн UTF-8

#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 не работает со значениями в разделе найти и заменить, потому что я еще не понимаю, как его использовать (все еще исследую), но это может быть так. Проблема в том, что я сопоставляю целые фразы на других языках, которые должны совпадать с полной фразой, чтобы заменить полную фразу. Они не находятся в одном и том же поле каждый раз или всегда в одном и том же порядке.