Почему использование шаблонов utf8 в операторах perl replace (s) и match (m) в однострочниках не работает?
Я обнаружил эту проблему при использовании однострочников Perl для замены текста utf8 в файлах. Мне известно о взломах в Как обрабатывать utf8 в командной строке (с использованием Perl или Python)?. В этом случае они не работают. ОС - linux, для параметра locate установлено значение utf8.
# make file to contain pattern
$echo Текст на юникоде>file
$cat file
Текст на юникоде
# also grep finds it
$grep "Текст на юникоде" file
Текст на юникоде
# different perl hacks mentioned at reference question don't work:
$perl -C63 -n -e "print if m{Текст на юникоде}" file
# does not show anything
$perl -Mutf8 -n -e "print if m{Текст на юникоде}" file
# does not show anything
# although it handles parameters correctly
$perl -e 'print "$ARGV[0]\n"' "Текст на юникоде"
Текст на юникоде
# and inside -e options as well
$perl -e 'print "Текст на юникоде\n"'
Текст на юникоде
# when create perl script to find the pattern, it works:
echo "while (<>) {print if m{Текст на юникоде}}">find.pl
$cat find.pl
while (<>) {print if m{Текст на юникоде}}
$perl find.pl file
Текст на юникоде
# and even this strange way it works:
perl -ne '$m="Текст на юникоде";print if m{$m}' file
Текст на юникоде
Итак, вот мой вопрос: есть ли более простое решение для использования шаблонов utf8 из операторов m и s с однострочными строками perl и почему простой подход не работает?
Спасибо!
Так, на всякий случай:
$uname -a
Linux ubuntu16-pereval 4.4.0-190-generic #220-Ubuntu SMP Fri Aug 28 23:02:15 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
$locale
LANG=en_US.UTF-8
LANGUAGE=en_US.UTF-8
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=en_US.UTF-8
1 ответ
perl -C63 -n -e "print if m{Текст на юникоде}" file
-C63
применяет различные флаги, чтобы сообщить Perl, что входные и выходные файлы находятся в UTF8.
perl -C63 -n -e "print if m{Текст на юникоде}" file
-Mutf8
сообщает компилятору Perl, что ваш исходный код находится в UTF8.
-C63
влияет на то, как Perl видит данные в
file
.
-Mutf8
влияет на то, как Perl видит код в вашем
-e
вариант. Чтобы Perl понял, что и входной файл, и исходный код должны интерпретироваться как UTF8, вам нужны оба варианта.
$ perl -Mutf8 -C63 -n -e "print if m{Текст на юникоде}" file
Текст на юникоде
Обновление: О, и я, вероятно, должен добавить, что самый простой вариант тоже работает (но по совершенно неправильным причинам!)
$ perl -n -e "print if m{Текст на юникоде}" file
Текст на юникоде
В этом случае это работает, потому что Perl интерпретирует как ввод, так и исходный код как состоящие из однобайтовых символов Latin-1. Пожалуйста, не делайте этого:-)