Доброго времени суток, друзья! Нашел себе занимательную задачку на ближайшее время, решил написать "звонилку" для Android. Приложение будет синхронизироваться с контактами в системе и выполнять определенные действия. При чем здесь quoted-printable, что это и зачем мне понадобилось — рассказываю в статье.
Итак, quoted-printable это система кодирования двоичного текста в текст, использующая печатаемые символы ASCII, и, судя по странице в английской версии википедии применяемая для кодирования/декодирования данных в сообщениях e-mail.
На самом деле это не совсем так. Есть такой формат файла — vCard. И именно в этом формате происходит импорт/экспорт контактов из любого смартфона с Android. Так вот, этот формат (имеющий расширение .vcf) в версии 2.1 также использует кодировку quoted-printable. Кириллица в этой кодировке имеет вид (пример): "=D0=9F=D1=80=D0=B8=D0=B2=D0=B5=D1=82"
, т.е. сначала каждый символ кириллицы кодируется в UTF-8 в последовательность из двух байтов, а затем каждый байт записывается в hex-представлении со знаком равно "=".
И вот в таком виде импортируются все контакты с кириллическими символами. Понятно что о чтении и редактировании файла речи не идет. А мне то как раз это и нужно. Попробовал через плагины в текстовых редакторах… Можно решить эту проблему, да, но уж слишком много манипуляций. Короче, пришлось засесть за написание декодера.
В процессе столкнулся с еще одной загвоздкой. Дело в том, что стандарт кодировки quoted-printable предусматривает строки максимальной длины в 75 символов, а потом делает переносы, дублируя символы "=". Понадобилась дополнительная функция для обьединения перенесенных строк.
Скрипт использует модуль quopri (у меня импортировался сразу, без установки).
import quopri
import os
List_contact = []
File = "Контакты.vcf"
with open (File) as file: # чтение файла с контактами
for i in file:
List_contact.append (i)
# функция для обьединения перенесенных строк
def Func (List_for_change):
List_contact_1 = []
for i in List_contact:
if i[-2] == '=':
List_contact_1.append (i[:-2])
else:
List_contact_1.append (i)
with open ('File.txt', 'w') as file:
for i in List_contact_1:
file.write (i)
List_contact_1 = []
with open ('File.txt') as file:
for i in file:
List_contact_1.append (i)
os.unlink ('File.txt') # удаление temp файла
return (List_contact_1)
List_contact = Func (List_contact)
#Запись декодированного текста в файл
with open ('Contacts_Decode.txt', 'w') as file:
for i in List_contact:
Str_1 = bytes (i, 'UTF-8') # модуль quopri принимает на вход двоичные данные
Str_2 = quopri.decodestring (Str_1)
file.write (Str_2.decode ('UTF-8'))
Итог работы скрипта. Из строк вида:
BEGIN:VCARD
VERSION:2.1
N;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:;=D0=90=D0=BD=D0=B4=D1=80=D0=
=B5=D0=B9;;;
FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=D0=90=D0=BD=D0=B4=D1=80=D0=
=B5=D0=B9
TEL;CELL;PREF:80000000000
END:VCARD
BEGIN:VCARD
VERSION:2.1
N;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:;=D0=92=D0=B8=D0=BA=D1=82=D0=
=BE=D1=80 =D0=9D=D0=B8=D0=BA=D0=BE=D0=BB=D0=B0=D0=B5=D0=B2=D0=B8=D1=87;;;
FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=D0=92=D0=B8=D0=BA=D1=82=D0=
=BE=D1=80 =D0=9D=D0=B8=D0=BA=D0=BE=D0=BB=D0=B0=D0=B5=D0=B2=D0=B8=D1=87
TEL;CELL;PREF:80000000000
END:VCARD
Получаем:
BEGIN:VCARD
VERSION:2.1
N;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:;Андрей;;;
FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:Андрей
TEL;CELL;PREF:80000000000
END:VCARD
BEGIN:VCARD
VERSION:2.1
N;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:;Виктор Николаевич;;;
FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:Виктор Николаевич
TEL;CELL;PREF:80000000000
END:VCARD
После редактирования файла при необходимости производим обратную кодировку:
List_contact_2 = []
with open('Contacts_Decode.txt') as file:
for i in file:
List_contact_2.append(i)
with open('Контакты_New.vcf', 'w') as file:
for i in List_contact_2:
Str_1 = bytes(i, 'UTF-8')
Str_2 = quopri.encodestring(Str_1)
Str_3 = Str_2.decode('UTF-8')
# quopri кодирует знак "=" в hex-значение "=3D", поэтому возвращаем его обратно
Str_4 = Str_3.replace('=3D','=')
file.write(Str_4)
На этом, по сути, можно было бы и закончить, но есть еще одна шутка штука. Показались мне строки, закодированые в quoted-printable странно похожими на некоторые url-адреса, которые каждый, пожалуй, встречал в адресной строке браузера, только вместо знака "=" со знаком "%". Вида (пример) "%D0%9F%D1%80%D0%B8%D0%B2%D0%B5%D1%82"
. И что бы вы думали? Да-да. По всей видимости это тоже quoted-printable (надо будет поинтересоваться у html-мастеров). Все декодируется в кириллицу вышеописанным способом при условии замены "%" на "=".
Ах да. Совсем забыл. Если вдруг кому то понадобится, то китайские иероглифы и арабские буквы декодируются так же как и кириллические символы (лично проверил).
Ну вот и все, друзья, до свидания, авось и будет от трудов моих кому то маленькая польза.
Tishka17
Не буду комментировать содержимое статьи. Но настоятельно рекомендую ознакомиться с PEP8. В частности, с правилами именования