Нормализация Unicode - имена файлов в текстовых файлах против имен файлов в файловой системе
Просто начинаю работать над одним приложением perl. Нужен совет, как (правильно) разобраться с unicode filenames
против filenames in the file content
портативный способ.
Вот несколько систем, в мире Windows и Unix используется различная кодировка Unicode (Unixes utf8, Windows - не знаю), но Linux и Mac OS X отличаются нормализацией Unicode для имен файлов. (OS X - принудительный NFD, Linux - "обычно" NFC).
Все советы, которые я уже прочитал, гласят: (всегда нормализуйте данные Юникода на границах приложения) - но вопрос в том, что является правильным - наиболее переносимым способом сделать это?
Проблема в том, что OS X (при создании текстовых файлов) использует NFC для контента. Я не знаю, что используют другие системы.
Итак, вопросы, что является правильным методом создания портативных приложений и работы с именами файлов в:
- opendir / READDIR
- glob и подобные "файловые операции"
- текстовые файлы (что будет содержать имена файлов)
- внутренние компоненты Perl...
- Другой?
Когда и где проводится нормализация? Как сохранить текстовые файлы utf8, что в их содержании содержатся имена файлов?
Я знаю, здесь много вопросов, связанных с perl-unicode, уже в StacOverflow. Я копал, вероятно, большинство из них - но до сих пор не понимаю, что такое "рекомендуемая" практика для решения приведенного выше списка вопросов.
Нужно ли будет делать модули для работы с конкретными отличиями операционной системы? Или здесь уже есть модули CPAN, которые имеют дело с различиями ОС в файловых операциях?)
Может кто-нибудь указать мне хороший ресурс с рекомендованными методами? Или это намного проще, чем я думаю сейчас?
2 ответа
Примечание. Запросы на сторонние ресурсы не рекомендуется использовать в Stackru. Кроме того, вопрос о том, как нормализовать текст Unicode в целом, слишком широк.
Относительно имен файлов, возвращаемых из readdir
или же glob
Хорошая практика - декодировать и нормализовать их. Рассмотрим следующий код:
#!/usr/bin/perl
use strict;
use utf8;
use File::Slurp;
use Unicode::Normalize;
binmode(STDOUT, ':utf8');
write_file("Unicode Test - Übersee.txt", "text");
opendir(my $dh, ".") or die($!);
while (my $entry = readdir($dh)) {
utf8::decode($entry);
if ($entry =~ /^Unicode Test - (.*)\.txt/) {
my $word = $1;
print("got $word\n");
print("matches 'Übersee': ", $word eq "Übersee" ? "yes" : "no", "\n");
my $nfc = NFC($word);
print("NFC matches 'Übersee': ", $nfc eq "Übersee" ? "yes" : "no", "\n");
}
}
closedir($dh);
На OS X это будет выводить:
got Übersee
matches 'Übersee': no
NFC matches 'Übersee': yes
Это связано с изменением NFD, которое HFS использует для нормализации имен файлов.
По сути, нормализуйте все входные данные из источников, где вы не можете быть уверены, что они в нормальной форме. В большинстве случаев вам следует использовать NFC, потому что большинство данных уже будет в NFC.
Насколько я могу судить, MS не проводит нормализацию в своей файловой системе. Это означает, что если вы планируете этот сценарий наихудшего случая, вы будете хороши на других ОС.
Техника, которая, кажется, работает, это запросить у ОС файлы, которые она видит. Создайте нормализованный хеш-код на основе нормализованной формы по вашему выбору и содержащий в качестве значений имена из ОС. Это не элегантно, но работает.