Приводим русские тексты на Mac OS X в одну кодировку Python-скриптом

в 22:04, , рубрики: CP1251, mac os x, OS X, python, Python 2.7, кодировки, метки: , , ,

Случилось мне иметь ноут на OS X, комп на Linux и одного из друзей с Windows. И вот через dropbox обмениваются все эти три компа документами разными. В том числе и текстовыми, в которых хранятся разные заметки, задачи и т.п. И вот незадача: тексты написанные на MacOSx плохо читаются в блокноте Винды, а виндовые в textedit на MacOSx.

И вся причина в том, что на винде блокнот использует кодировку Windows 1251, а на OS X используется по умолчанию MACCYRILLIC. Причем обе программы без проблем работают с UTF-8 кодировкой.
Вот только конвертировать из одной кодировки в другую как-то неудобно, лишнее время тратить на открытие терминала и набор заветных команд iconv…

Пораздумав, написал небольшой скрипт, который сам определяет используемую кодировку и конвертирует в UTF-8 все txt-файлы.

Определение происходит простым перебором кодировок и выбором той, в которой не будет лишних символов. А набор символов определяете Вы. Конечно этот способ не подойдет для файлов с DOS-графикой, но в обычных целях использования txt его вполне хватит.

Что использую для всего:
Python 2.7
Mac OS X 10.7.5
PyCharm IDE

#!/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-=—+_}{][\"|;:'/?><.,`~§±!@#$%^&*()№ rn « » 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. nn')


    if toconvert:
        c=0
        for i in toconvert:
            if i[1]!=u'NOT FOUND ENCODING':
                c+=1
        if c>0:
            print1(u'nn 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')


Далее необходимо сделать удобным запуск данного скрипта прямо из папки в OS X.

Открываем Automator и создаем Службу.
Вверху выбираем пункты, чтобы получилось «Служба получает файлы и папки в Finder.app».

Далее ставим действие «получить выбранные объекты Finder».
Далее «Запустить Shell-скрипт» и в нем содержание:

for f in "$@"
do
	python /ПУТЬ_К_ВАШЕМУ_СКРИПТУ/convert_encoding.py "$f"
done

И последний пункт «Show Growl Notification» (в нем можно написать, что конвертация произведена).
Приводим русские тексты на Mac OS X в одну кодировку Python скриптом

Сохраняем с именем латинскими буквами (с русскими у меня почему-то пункт в меню не появлялся, пока не переименовал) и проверяем.

Новый пункт меню появится в Finder в меню файлов и папок в подменю Сервисы.

Автор: virtustilus


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js