Вопрос или проблема
Я стандартизирую название нескольких файлов одновременно, поэтому я написал регулярное выражение для perl-rename
:
perl-rename 'y/A-Z/a-z/; s/ã|á|â/a/g; s/é|ê/e/g; s/í/i/g; s/õ|ó/o/g; s/ú/u/g; s/ç/c/g; s/(?<=\d-)*\s/_/g; s/_+/_/g; s/(?<=\d)_/-/' *
Это работает именно так, как и ожидалось:
2024-12-01 certidão de matrícula -> 2024-12-01-certidao_de_matricula
Тем не менее, я подумал, что это можно немного упростить, и придумал это:
perl-rename 'y/A-Z/a-z/; y/ãáâéêíõóúç/aaaeeioouc/; s/(?<=\d-)*\s/_/g; s/_+/_/g; s/(?<=\d)_/-/' *
Результаты, однако, не оправдали моих ожиданий. Например:
2024-12-01 certidão de matrícula -> 2024-12-01-certidaao_de_matraccula
Почему вторая команда не работает, если она должна выполнять прямую транслитерацию каждого ударного символа? Я даже не могу понять результат. Заранее спасибо.
Это происходит, потому что Perl не знает, что он должен обрабатывать имена файлов как UTF-8. Вместо этого он смотрит на отдельные байты, поэтому вы получаете частичные замены и дубликаты. Например, рассмотрим это:
% echo 'ä:ö:ä' | perl -pe 'y/ä/x/'
xx:x�:xx
Здесь ввод равен \xc3\xa4:\xc3\xb6:\xc3\xa4
, и y/ä/x/
принимается как y/\xc3\xa4/x/
(с правой стороны x
неявно дублируется). В результате UTF-8 ä
превращается в xx
, когда оба байта заменяются индивидуально, и UTF-8 ö
ломается, когда заменяется только первый байт.
Команда s///
работает, потому что она ищет целую строку для замены, поэтому не имеет значения, интерпретируется ли она как один символ или два байта.
Вы можете исправить это, добавив use utf8
или -Mutf8
, чтобы сказать Perl, что источник в UTF-8, и опцию -C
, чтобы сообщить ему, что stdin/stdout в UTF-8.
% echo 'ä:ö:ä' | perl -Mutf8 -C -pe 'y/ä/x/'
x:ö:x
В скрипте переименования вы, вероятно, не сможете использовать -C
, поэтому используйте переменную окружения PERL_UNICODE
, например, с export PERL_UNICODE=AS
(для аргументов и stdin/out), и включите use utf8
в вашу команду переименования и надеетесь, что это сработает.
Ответ или решение
Чтобы заменить акцентированные символы в названиях файлов с помощью утилиты perl-rename
, вам необходимо правильно настроить кодировку, чтобы Perl корректно обрабатывал ваши данные как UTF-8. В вашем первом примере вы используете два разных подхода:
- Использование
s///
для замены отдельных акцентированных символов. - Использование
y///
для трансляции символов.
Проблема в вашем втором подходе заключается в том, что Perl не интерпретирует файлы как UTF-8, а обрабатывает каждый байт отдельно, что приводит к некорректным заменам.
Причина некорректной работы
В вашем упрощённом варианте с использованием y/ãáâéêíõóúç/aaaeeioouc/
вы столкнулись с тем, что Perl видит не целые символы, а отдельные байты. В результате этого, когда UTF-8 символ мадрекций, такой как ä
, заменяется, только его первый байт затрагивается, что приводит к неожиданным результатам.
Пример
Рассмотрим пример:
echo 'ä:ö:ä' | perl -pe 'y/ä/x/'
Результат будет
xx:x�:xx
Это связано с тем, что ä
соответствует байтам \xc3\xa4
, и Perl заменяет его на x
, который занимает один байт, что приводит к возникновению ошибки при интерпретации выходного символа.
Решение проблемы
Настройка кодировки
Чтобы добиться корректной работы и избежать проблем с неверной интерпретацией символов, вы можете использовать следующие подходы.
-
Использование модуля
utf8
: Добавьте в ваш код строкуuse utf8;
для указания той кодировки, с которой будет работать Perl. -
Параметры окружения: Установите переменную окружения
PERL_UNICODE
, чтобы информировать Perl о том, что входные и выходные данные должны обрабатываться как UTF-8.
Пример корректного использования perl-rename
:
export PERL_UNICODE=AS
perl-rename 'use utf8; y/A-Z/a-z/; y/ãáâéêíõóúç/aaaeeioouc/; s/(?<=\d-)*\s/_/g; s/_+/_/g; s/(?<=\d)_/-/' *
Заключение
Проблема, с которой вы столкнулись, связана с неверным обращением Perl к кодировке файлов. Чтобы избежать таких ошибок, всегда следите за настройками кодировки при работе с многоязычными данными. Используйте use utf8;
и соответствующие параметры окружения для корректной работы с UTF-8. Следуя представленным рекомендациям, вы сможете успешно стандартизировать имена файлов и избежать неожиданных результатов в будущем.