perltidy и cp1251

от автора

В 2000-х определилась тенденция переводить проекты в национальных кодировках в utf-8. Однако не везде их перевели одним махом, а решили рубить собаке хвост постепенно. В результате во многих проектах часть файлов c кодом в utf-8, а часть осталась в национальной кодировке (например, cp1251).

Поэтому я сделал утилиту ru-perltidy, которая определяет кодировку файлов, конвертирует в utf-8, а после форматирования переводит обратно.

Из вкусносей тут то, что ru-perltidy может отформатировать только изменённые в репозитории git файлы (Рис.1).

Рис.1. Установка утилиты и форматирование ею только изменённых файлов.
Рис.1. Установка утилиты и форматирование ею только изменённых файлов.

Если же файлы были закомичены: не беда — укажите опцию —in-branch и ru-perltidy отформатирует все изменённые файлы в ветке воспользовавшись командой :

git diff --name-only --diff-filter=AM origin/master...

Имеет команда и несколько иных опций:

# Отформатировать указанные файлы perltidy: $ ru-perltidy file1 file2  # Указать кодировку: $ ru-perltidy file1 file2 -e utf-8,cp1251  # Форматирует только изменённые файлы в репозитории git: $ ru-perltidy  # Форматирует изменённые файлы в ветке    # (на случай, если забыл отформатировать перед комитом): $ ru-perltidy --in-branch  # Указать расширения файлов: $ ru-perltidy --ext 'pl,pm,'

Впрочем может понадобится и другая операция, а не только perltidy. Поэтому я добавил в пакет утилиту ru-utf8. Она аналогична ru-perltidy, но требует указания обязательной опции в которой передаётся команда для обработки переведённых в utf-8 файлов. А после выполнения команды файлы переписывается обратно, в той же кодировке, в которой и были.

# Перевести файлы во временные в кодировке utf-8 (в /tmp) и после выполнения команды    # и их изменения переписать обратно в определённой кодировке: # (тут $1 - первый файл, $2 - второй и т.д., $* - все файлы через пробел.    # Так же работают подстановки ${1} и т.д.) $ ru-utf8 file1 file2 -c 'perltidy $1 -st > /tmp/1 && mv /tmp/1 $1'

Алгоритм определения кодировки файла

Для определения кодировки файла используется следующий алгоритм:

  1. Файл считывается и декодируется в указанных кодировках (по-умолчанию это utf-8, cp1251 и koi8-r).

  2. Затем в декодированных вариантах текста подсчитываются длины русских слов начинающиеся с прописной или строчной буквы и далее из строчных.

  3. Длины русских слов не подпадающих под указанный критерий вычитаются из результата.

  4. Набравший наибольший балл декодированный результат и будет правильным.

Вот реализация этого алгоритма на perl:

#@category Кодировка  # Определяет кодировку. # В koi8-r и в cp1251 большие и малые буквы как бы поменялись местами,  # поэтому у правильной кодировки вес будет больше sub bohemy($) {     my ($s) = @_;     my $c = 0;     while ( $s =~ /[а-яё]+/gi ) {         my $x = $&;         if   ( $x =~ /^[А-ЯЁа-яё][а-яё]*$/ ) { $c += length $x }         else                                 { $c -= length $x }     }     $c; }  # Определить кодировку и декодировать sub decode(@) {     my ( $octets, $encodings ) = @_;      return if !length $octets;      utf8::encode($octets) if utf8::is_utf8($octets);      $encodings //= [qw/utf-8 cp1251 koi8-r/];      my @x = grep length $_->[0], map {      # TODO: В случае ошибки Encode::decode помещает пустую строку в свой     # второй аргумент. Сейчас это исправлено копированием значения в         # дополнительную переменную, но было бы неплохо разобраться в причине.         my $save = $octets;         eval { [ Encode::decode( $_, $save, Encode::FB_CROAK ), $_ ] };     } @$encodings;      my ( $unicode, $mem_encoding );     ( $unicode, $mem_encoding ) = @{ $x[0] } if @x == 1;      if ( @x > 1 ) {         ( $unicode, $mem_encoding ) =           @{ ( sort { bohemy( $b->[0] ) <=> bohemy( $a->[0] ) } @x )[0] };     }      wantarray ? ( $unicode, $mem_encoding ) : $unicode; }

Заключение

Во время разработки у нас накапливается множество мест за которыми приходится следить и исправлять их рутинными, но трудоёмкими действиями. Поэтому, если такие места невозможно, по каким-то причинам, убрать из проекта, то лучше слежку и связанные с ними действия автоматизировать.

Ссылки

  1. Модуль Octets::To::Unicode на CPAN / https://metacpan.org/pod/Octets::To::Unicode.

  2. ru-perltidy на github / https://github.com/darviarush/perl-octets-to-unicode.


ссылка на оригинал статьи https://habr.com/ru/post/664308/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *