Случилось мне иметь ноут на OS X, комп на Linux и одного из друзей с Windows. И вот через dropbox обмениваются все эти три компа документами разными. В том числе и текстовыми, в которых хранятся разные заметки, задачи и т.п. И вот незадача: тексты написанные на MacOSx плохо читаются в блокноте Винды, а виндовые в textedit на MacOSx.
И вся причина в том, что на винде блокнот использует кодировку Windows 1251, а на OS X используется по умолчанию MACCYRILLIC. Причем обе программы без проблем работают с UTF-8 кодировкой.
Вот только конвертировать из одной кодировки в другую как-то неудобно, лишнее время тратить на открытие терминала и набор заветных команд iconv…
Пораздумав, написал небольшой скрипт, который сам определяет используемую кодировку и конвертирует в UTF-8 все txt-файлы.
Что использую для всего:
Python 2.7
Mac OS X 10.7.5
PyCharm IDE
Изначально сделал определение кодировки самостоятельно, без дополнительных модулей. Но по совету ad3w решил переписать с использованием готового модуля chardet для определения кодировки.
Кому интересно, предыдущий
Скачиваем модуль chardet 1.1,
Распаковываем и устанавливаем:
Создаем свой скрипт для перекодировки файлов:
Далее необходимо сделать удобным запуск данного скрипта прямо из папки в OS X.
Открываем Automator и создаем Службу.
Вверху выбираем пункты, чтобы получилось «Служба получает файлы и папки в Finder.app».
Далее ставим действие «получить выбранные объекты Finder».
Далее «Запустить Shell-скрипт» в настройках его «Передать ввод: как аргументы» и в нем содержание:
Дописал 2>/dev/null, чтобы автоматор не останавливал выполнение при выводе ошибки модуля chardet.
И последний пункт «Show Growl Notification» (в нем можно написать, что конвертация произведена).

Сохраняем с именем латинскими буквами (с русскими у меня почему-то пункт в меню не появлялся, пока не переименовал) и проверяем.
Новый пункт меню появится в Finder в меню файлов и папок в подменю Сервисы.
P.S. Это уже 5-ая редакция скрипта после комментариев и опыта его использования.
P.S. Обнаружил проблему: если питон увидит кодировку файла, в который пишет, то он в ней и будет работать. Нам это не нужно, поэтому удаляем файл перед сохранением.
И вся причина в том, что на винде блокнот использует кодировку Windows 1251, а на OS X используется по умолчанию MACCYRILLIC. Причем обе программы без проблем работают с UTF-8 кодировкой.
Вот только конвертировать из одной кодировки в другую как-то неудобно, лишнее время тратить на открытие терминала и набор заветных команд iconv…
Пораздумав, написал небольшой скрипт, который сам определяет используемую кодировку и конвертирует в UTF-8 все txt-файлы.
Что использую для всего:
Python 2.7
Mac OS X 10.7.5
PyCharm IDE
Изначально сделал определение кодировки самостоятельно, без дополнительных модулей. Но по совету ad3w решил переписать с использованием готового модуля chardet для определения кодировки.
Кому интересно, предыдущий
ужасный код
Определение происходит простым перебором кодировок и выбором той, в которой не будет лишних символов. А набор символов определяете Вы. Конечно этот способ не подойдет для файлов с DOS-графикой, но в обычных целях использования txt его вполне хватит.
#!/usr/bin/python # -*- coding: utf-8 -*- __author__ = 'virtustilus' import os import sys #Автоматический режим при запуске с параметрами automatic=False #общие данные appdata={'enc':'','curfile':''} #Массив файлов для конвертации toconvert=[] #массив на загрузку r=[] if len(sys.argv)>1: r=sys.argv[1:] automatic=True else: i=raw_input(u'INPUT PATH:') r+=[i] def print1(s): """ Функция печатает данные, если не в автоматическом режиме """ if not automatic: print s #Строка с возможными символами utfrustring=u'АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзийклмнопрстуфхцчшщъыьэюя' utfrustring+=u'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' utfrustring+=u'1234567890-=—+_}{][\\"|;:\'/?><.,`~§±!@#$%^&*()№ \r\n « » \u0009 \u2013 \u201c \u201d' def checkline(s,encoding=''): """ проверка одной строки на правильность символов """ hist='' b=True for i in range(0,len(s)): c=s[i] try: if not c in utfrustring: #Отладка: если в UTF-8 кодировке неверный символ, лучше его показать if encoding==u'UTF-8': hist+= c + u' ' + str(hex(ord(c))) + u' at ' + str(i) + u' in: ' + s + '\n' b=False break except: if encoding==u'UTF-8': hist+=u'error encoding \n' b=False break return (b,hist) def check_all_lines(lines, encoding=''): """ Проверка массива строк для файла """ foundenc=appdata['enc'] if foundenc: return foundenc if encoding=='': foundenc=u'UNICODE' else: foundenc=encoding x=lines[:] for j in x: if encoding!='': try: j=unicode(j,encoding) except: foundenc='' break cl=checkline(j,encoding) if not cl[0]: if cl[1]!='': print1(u'Error in:'+appdata['curfile']) print1(cl[1]) foundenc='' break appdata['enc']=foundenc #Если передана директория, а не файл, собрать все входящие текстовые файлы if len(r)==1 and os.path.isdir(r[0]): a=r[0] r[:]=[] for i in os.walk(a): p=i[2] for j in p: if j.endswith('.txt'): r+=[i[0]+'/'+j] if len(r)>0: for i in r: i=unicode(i,u'UTF-8') #обратите внимание, тут конвертация имени файла в UNICODE и проверка txt также в UNICODE: u'.txt' if i.endswith(u'.txt'): f=file(i,'r') lines=f.readlines() f.close() appdata['curfile']=i #Проверяем некоторые кириллические кодировки check_all_lines(lines,'') check_all_lines(lines,u'MACCYRILLIC') check_all_lines(lines,u'CP866') check_all_lines(lines,u'CP1251') check_all_lines(lines,u'KOI8R') check_all_lines(lines,u'CP10007') check_all_lines(lines,u'UTF-8-MAC') check_all_lines(lines,u'UTF-8') check_all_lines(lines,u'UTF-8-MAC') check_all_lines(lines,u'UTF-16') check_all_lines(lines,u'UTF-16BE') check_all_lines(lines,u'UTF-7') check_all_lines(lines,u'CP1252') check_all_lines(lines,u'KOI8-U') check_all_lines(lines,u'KOI8-RU') check_all_lines(lines,u'ISO-8859-5') if not appdata['enc']: toconvert.append((i,u'NOT FOUND ENCODING')) if appdata['enc'] and appdata['enc']!=u'UTF-8': toconvert.append((i,appdata['enc'])) else: print1(u'\nFile '+i+u' is not text file. \n\n') if toconvert: c=0 for i in toconvert: if i[1]!=u'NOT FOUND ENCODING': c+=1 if c>0: print1(u'\n\n FOUND FILES TO CONVERT: ') for i in toconvert: print1(i[0] + u' in encoding ' + i[1]) bt=True if not automatic: w=raw_input(u'Convert '+str(c)+u' files? (N)') bt= (w=='Y' or w=='y' or w=='Д' or w=='д' or w=='да' or w=='Да') if bt: for i in toconvert: if i[1]!=u'NOT FOUND ENCODING': f=file(i[0],'r') x=f.readlines() f.close() x=[ unicode(k,i[1]) for k in x ] x=[ k.encode(u'UTF-8') for k in x] f=file(i[0],'w') f.writelines(x) f.close() print1(u'FILE '+i[0]+u' CONVERTED SUCCESSFULLY :) ') else: print1(u'Bye!') else: print1(u'NO FILES TO CONVERT') for i in toconvert: print1(i[0] + u' in encoding ' + i[1]) else: print1(u' ALL ENCODING IS OK (UTF-8)!!! :)') else: print1(u'NO ONE TXT FILE')
Скачиваем модуль chardet 1.1,
Распаковываем и устанавливаем:
python setup.py install
Создаем свой скрипт для перекодировки файлов:
Предыдущая редакция
#!/usr/bin/python # -*- coding: utf-8 -*- __author__ = 'virtustilus' import os import sys import chardet files=sys.argv[1:] #если запуск без параметров, запрашиваем путь if len(files)==0: files=[raw_input(u'INPUT PATH:')] #собираем текстовые файлы и проходим по папкам files_to_convert=[] for i in files: if os.path.exists(i): if os.path.isdir(i): for w in os.walk(i): for wfile in w[2]: if wfile.lower().endswith('.txt'): files_to_convert+=[w[0]+'/'+wfile] elif os.path.isfile(i): #если был выбран файл специально, не важно какое расширение files_to_convert+=[i] if len(files_to_convert)>0: for i in files_to_convert: f=file(i,'r') text=''.join(f.readlines()) f.close() enc=chardet.detect(text).get('encoding') #Чтобы лишний раз не перезаписывать файл (dropbox), проверяем его кодировку if enc!='UTF-8': #Обходим ошибку перекодировки файла при пустом файле или другом случае try: text=text.decode(enc).encode('UTF-8') f=file(i,'w') f.write(text) f.close() except: pass
#!/usr/bin/python # -*- coding: utf-8 -*- __author__ = 'virtustilus' import os import sys import chardet def may_be_1251(text_not_changed, encoding): """ Функция проверяет возможность Win1251, если chardet написал, что это MacCyrillic И возвращает кодировку Например в данном тексте chardet считает, что это MacCyrillic: 1. ”становить пробную Advanced-версию 2. ”бедитьс€, что программа закрыта (в т.ч. и агент в области уведомлений) 3. —копировать библиотеку mfc100u.dll в папку с программой и согласитьс€ на замену """ simbols = u'АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзийклмнопрстуфхцчшщъыьэюя' simbols += u'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' simbols += u'1234567890-=—+_}{][\\"|;:\'/?><.,`~§±!@#$%^&*()№ \r\n' if encoding.lower() == 'maccyrillic': err_mac = err_win = 0 try: t_win = text_not_changed.decode('cp1251') except: err_win += 1000000 try: t_mac = text_not_changed.decode('MacCyrillic') except: err_mac += 1000000 for i in t_win: if i not in simbols and i != u'\n': err_win += 1 for i in t_mac: if i not in simbols: err_mac += 1 if err_mac > err_win: encoding = 'cp1251' return encoding paths = sys.argv[1:] #если запуск без параметров, запрашиваем путь if len(paths) == 0: paths = [raw_input(u'INPUT PATH:')] #выбираем директории и файлы (файлы любые, т.к. они были выбраны пользователем "не зря") dirs = [i for i in paths if os.path.exists(i) and os.path.isdir(i)] files = [i for i in paths if os.path.exists(i) and os.path.isfile(i)] #рекурсивно проходим по поддиректориям for i_dir in dirs: for wpath, wdirs, wfiles in os.walk(i_dir): files += [wpath + '/' + i for i in wfiles if i.lower().endswith('.txt')] for i in files: with open(i, 'r') as f: text = ''.join(f.readlines()) enc = may_be_1251(text, chardet.detect(text).get('encoding')) #Чтобы лишний раз не перезаписывать файл (dropbox), проверяем его кодировку if enc and enc.lower() != 'utf-8': #Обходим ошибку перекодировки файла при пустом файле или другом случае try: text = text.decode(enc) #На новой версии OS X 10.8 текстедиту не нравятся символы \r text = text.replace(u'\r', '').encode('utf-8') #Обнаружил проблему: если питон увидит кодировку, то он в ней и будет работать. Нам это не нужно, поэтому удаляем файл os.unlink(i) with open(i, 'w') as f: f.write(text) except: pass
Далее необходимо сделать удобным запуск данного скрипта прямо из папки в OS X.
Открываем Automator и создаем Службу.
Вверху выбираем пункты, чтобы получилось «Служба получает файлы и папки в Finder.app».
Далее ставим действие «получить выбранные объекты Finder».
Далее «Запустить Shell-скрипт» в настройках его «Передать ввод: как аргументы» и в нем содержание:
for f in "$@" do python /ПУТЬ_К_ВАШЕМУ_СКРИПТУ/convert_encoding.py "$f" 2>/dev/null done
Дописал 2>/dev/null, чтобы автоматор не останавливал выполнение при выводе ошибки модуля chardet.
И последний пункт «Show Growl Notification» (в нем можно написать, что конвертация произведена).

Сохраняем с именем латинскими буквами (с русскими у меня почему-то пункт в меню не появлялся, пока не переименовал) и проверяем.
Новый пункт меню появится в Finder в меню файлов и папок в подменю Сервисы.
P.S. Это уже 5-ая редакция скрипта после комментариев и опыта его использования.
P.S. Обнаружил проблему: если питон увидит кодировку файла, в который пишет, то он в ней и будет работать. Нам это не нужно, поэтому удаляем файл перед сохранением.
