Perl Проклятия и юникод: почему addstr печатает нормально, а addstring — мусор?

addstr — код, вывод:

use Curses;
initscr;
addstr 0, 0, 'Ж 会 र';
addstr 1, 0, 'Curses ' . Curses->VERSION . ", perl $^V" . ", OS: $^O";
getch;
endwin;
Ж 会 र
Curses 1.43, perl v5.36.0, OS: openbsd

addstring — код, вывод:

use Curses;
initscr;
addstring 0, 0, 'Ж 会 र';
addstring 1, 0, 'Curses ' . Curses->VERSION . ", perl $^V" . ", OS: $^O";
getchar;
endwin;
Ð~V ä¼~Z र
Curses 1.43, perl v5.36.0, OS: openbsd

Почему наблюдается такое поведение?
Разве не должно быть наоборот, поскольку addstr является устаревшим, а addstring предназначен для поддержки юникода?

https://metacpan.org/pod/Curses#Wide-Character-Aware-Functions
https://metacpan.org/pod/Curses#Available-Wide-Character-Aware-Functions


Обновлять:

Более широкий пример со строкой юникода:

  • жестко закодированный,
  • взято из переменной
  • передается как аргумент CLI
  • читать из файла через обратные кавычки
  • читать из файла через open

Нам нужен файл со строкой в ​​юникоде:

echo -n 'Ж 会 र' > unicode.string.txt

Случай 1: addstr, без дополнительных объявлений:

use Curses;

my $unicode_string_variable  = 'Ж 会 र';
my $unicode_string_argv      = $ARGV[0];
my $unicode_string_backticks = `cat unicode.string.txt`;
open my $open_pipe_read_handle, '-|', 'cat', 'unicode.string.txt' || die;
my $unicode_string_open_pipe = <$open_pipe_read_handle>;

# print unicode to files
open my $hardcoded_handle, '>', 'unicode.string.hardcoded' || die;
  print $hardcoded_handle 'Ж 会 र';
  close $hardcoded_handle;
open my  $variable_handle, '>', 'unicode.string.variable'  || die;
  print  $variable_handle $unicode_string_variable;
  close  $variable_handle;
open my      $argv_handle, '>', 'unicode.string.argv'      || die;
  print      $argv_handle $unicode_string_argv;
  close      $argv_handle;
open my $backticks_handle, '>', 'unicode.string.backticks' || die;
  print $backticks_handle $unicode_string_backticks;
  close $backticks_handle;
open my $open_pipe_handle, '>', 'unicode.string.open_pipe' || die;
  print $open_pipe_handle $unicode_string_open_pipe;
  close $open_pipe_handle;

# print unicode to STDOUT
printf "%s: %s\n", 'hardcoded', 'Ж 会 र';
printf "%s: %s\n", 'variable ', $unicode_string_variable;
printf "%s: %s\n", 'argv     ', $unicode_string_argv;
printf "%s: %s\n", 'backticks', $unicode_string_backticks;
printf "%s: %s\n", 'open_pipe', $unicode_string_open_pipe;

initscr;

# print unicode to Curses
addstr 0, 0, 'hardcoded: ' . 'Ж 会 र';
addstr 1, 0, 'variable : ' . $unicode_string_variable;
addstr 2, 0, 'argv     : ' . $unicode_string_argv;
addstr 3, 0, 'backticks: ' . $unicode_string_backticks;
addstr 4, 0, 'open_pipe: ' . $unicode_string_open_pipe;

addstr 5, 0, 'Curses ' . Curses->VERSION . ", perl $^V" . ", OS: $^O";

getchar;
endwin;

бегать:

perl curses-unicode.addstr.pl 'Ж 会 र'

Вывод ругательств, всерабочий юникод:

hardcoded: Ж 会 र
variable : Ж 会 र
argv     : Ж 会 र
backticks: Ж 会 र
open_pipe: Ж 会 र
Curses 1.43, perl v5.36.0, OS: openbsd

Выход STDOUT, всерабочий юникод:

hardcoded: Ж 会 र
variable : Ж 会 र
argv     : Ж 会 र
backticks: Ж 会 र
open_pipe: Ж 会 र

Вывод файлов, всерабочий юникод:

cat unicode.string.*
Ж 会 रЖ 会 रЖ 会 रЖ 会 रЖ 会 रЖ 会 र

Случай 2: addstring, без дополнительных объявлений:

use Curses;

my $unicode_string_variable  = 'Ж 会 र';
my $unicode_string_argv      = $ARGV[0];
my $unicode_string_backticks = `cat unicode.string.txt`;
open my $open_pipe_read_handle, '-|', 'cat', 'unicode.string.txt' || die;
my $unicode_string_open_pipe = <$open_pipe_read_handle>;

# print unicode to files
open my $hardcoded_handle, '>', 'unicode.string.hardcoded' || die;
  print $hardcoded_handle 'Ж 会 र';
  close $hardcoded_handle;
open my  $variable_handle, '>', 'unicode.string.variable'  || die;
  print  $variable_handle $unicode_string_variable;
  close  $variable_handle;
open my      $argv_handle, '>', 'unicode.string.argv'      || die;
  print      $argv_handle $unicode_string_argv;
  close      $argv_handle;
open my $backticks_handle, '>', 'unicode.string.backticks' || die;
  print $backticks_handle $unicode_string_backticks;
  close $backticks_handle;
open my $open_pipe_handle, '>', 'unicode.string.open_pipe' || die;
  print $open_pipe_handle $unicode_string_open_pipe;
  close $open_pipe_handle;

# print unicode to STDOUT
printf "%s: %s\n", 'hardcoded', 'Ж 会 र';
printf "%s: %s\n", 'variable ', $unicode_string_variable;
printf "%s: %s\n", 'argv     ', $unicode_string_argv;
printf "%s: %s\n", 'backticks', $unicode_string_backticks;
printf "%s: %s\n", 'open_pipe', $unicode_string_open_pipe;

initscr;

# print unicode to Curses
addstring 0, 0, 'hardcoded: ' . 'Ж 会 र';
addstring 1, 0, 'variable : ' . $unicode_string_variable;
addstring 2, 0, 'argv     : ' . $unicode_string_argv;
addstring 3, 0, 'backticks: ' . $unicode_string_backticks;
addstring 4, 0, 'open_pipe: ' . $unicode_string_open_pipe;

addstring 5, 0, 'Curses ' . Curses->VERSION . ", perl $^V" . ", OS: $^O";

getchar;
endwin;

бегать:

perl curses-unicode.addstring.pl 'Ж 会 र'

Вывод ругательств, весь битый юникод::

hardcoded: Ð~V ä¼~Z र
variable : Ð~V ä¼~Z र
argv     : Ð~V ä¼~Z र
backticks: Ð~V ä¼~Z र
open_pipe: Ð~V ä¼~Z र
Curses 1.43, perl v5.36.0, OS: openbsd

Вывод STDOUT, всерабочий юникод::

hardcoded: Ж 会 र
variable : Ж 会 र
argv     : Ж 会 र
backticks: Ж 会 र
open_pipe: Ж 会 र

Вывод файлов, всерабочий юникод:

cat unicode.string.*
Ж 会 रЖ 会 रЖ 会 रЖ 会 रЖ 会 रЖ 会 र

Случай 3: addstring, дополнительные объявления use utf8, -CA и :encoding(UTF-8):

use utf8;
use Curses;

my $unicode_string_variable  = 'Ж 会 र';
my $unicode_string_argv      = $ARGV[0];
my $unicode_string_backticks = `cat unicode.string.txt`;
open my $open_pipe_read_handle, '-|:encoding(UTF-8)', 'cat', 'unicode.string.txt' || die;
my $unicode_string_open_pipe = <$open_pipe_read_handle>;

# print unicode to files
open my $hardcoded_handle, '>', 'unicode.string.hardcoded' || die;
  print $hardcoded_handle 'Ж 会 र';
  close $hardcoded_handle;
open my  $variable_handle, '>', 'unicode.string.variable'  || die;
  print  $variable_handle $unicode_string_variable;
  close  $variable_handle;
open my      $argv_handle, '>', 'unicode.string.argv'      || die;
  print      $argv_handle $unicode_string_argv;
  close      $argv_handle;
open my $backticks_handle, '>', 'unicode.string.backticks' || die;
  print $backticks_handle $unicode_string_backticks;
  close $backticks_handle;
open my $open_pipe_handle, '>', 'unicode.string.open_pipe' || die;
  print $open_pipe_handle $unicode_string_open_pipe;
  close $open_pipe_handle;

# print unicode to STDOUT
printf "%s: %s\n", 'hardcoded', 'Ж 会 र';
printf "%s: %s\n", 'variable ', $unicode_string_variable;
printf "%s: %s\n", 'argv     ', $unicode_string_argv;
printf "%s: %s\n", 'backticks', $unicode_string_backticks;
printf "%s: %s\n", 'open_pipe', $unicode_string_open_pipe;

initscr;

# print unicode to Curses
addstring 0, 0, 'hardcoded: ' . 'Ж 会 र';
addstring 1, 0, 'variable : ' . $unicode_string_variable;
addstring 2, 0, 'argv     : ' . $unicode_string_argv;
addstring 3, 0, 'backticks: ' . $unicode_string_backticks;
addstring 4, 0, 'open_pipe: ' . $unicode_string_open_pipe;

addstring 5, 0, 'Curses ' . Curses->VERSION . ", perl $^V" . ", OS: $^O";

getchar;
endwin;

бегать:

perl -CA curses-unicode.addstring.utf8,CA,encodingUTF8.pl 'Ж 会 र'

Вывод проклятий, частично рабочий, частично битый юникод::

hardcoded: Ж 会 र
variable : Ж 会 र
argv     : Ж 会 र
backticks: Ð~V ä¼~Z र
open_pipe: Ж 会 र
Curses 1.43, perl v5.36.0, OS: openbsd

Выход STDOUT&STDERR, всерабочий юникод:

Wide character in print at curses-unicode.addstring.utf8,CA,encodingUTF8.pl line 12, <$open_pipe_read_handle> line 1.
Wide character in print at curses-unicode.addstring.utf8,CA,encodingUTF8.pl line 15, <$open_pipe_read_handle> line 1.
Wide character in print at curses-unicode.addstring.utf8,CA,encodingUTF8.pl line 18, <$open_pipe_read_handle> line 1.
Wide character in print at curses-unicode.addstring.utf8,CA,encodingUTF8.pl line 24, <$open_pipe_read_handle> line 1.
Wide character in printf at curses-unicode.addstring.utf8,CA,encodingUTF8.pl line 28, <$open_pipe_read_handle> line 1.
hardcoded: Ж 会 र
Wide character in printf at curses-unicode.addstring.utf8,CA,encodingUTF8.pl line 29, <$open_pipe_read_handle> line 1.
variable : Ж 会 र
Wide character in printf at curses-unicode.addstring.utf8,CA,encodingUTF8.pl line 30, <$open_pipe_read_handle> line 1.
argv     : Ж 会 र
backticks: Ж 会 र
Wide character in printf at curses-unicode.addstring.utf8,CA,encodingUTF8.pl line 32, <$open_pipe_read_handle> line 1.
open_pipe: Ж 会 र

Вывод файлов, всерабочий юникод:

cat unicode.string.*
Ж 会 रЖ 会 रЖ 会 रЖ 会 रЖ 会 रЖ 会 र

  • Почему юникод работает только для STDOUT и записывает в файлы во всех 3 случаях без каких-либо проблем, тогда как Curses мешает? Что особенного в Curses? Не является ли это какой-то ошибкой в ​​Curses, учитывая, что с STDOUT и файлами все в порядке?
  • Есть ли одно место для включения юникода или вам нужно указать отдельно; где однородность; почему?:
    • use utf8 для юникода в исходнике;
    • -CA для аргументов cli;
    • :encoding(UTF-8) за open
  • Как исправить юникод для обратных кавычек?
  • Что такое Wide character in print at curses-unicode.addstring.utf8,CA,encodingUTF8.pl line ..., <$open_pipe_read_handle> line 1. на STDERR и как от них избавиться?
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
0
54
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вам нужна прагма use utf8;:

use utf8;
use Curses;
initscr;
addstring 0, 0, 'Ж 会 र';
addstring 1, 0, 'Curses ' . Curses->VERSION . ", perl $^V" . ", OS: $^O";
getch;
endwin;

Выход:

Ж 会 र
Curses 1.43, perl v5.34.0, OS: linux

См. Часто задаваемые вопросы о Perl Unicode. Почему работает версия addstr, наверное, дело везения (в моей системе корректно отображается только третий символ).

Если вы хотите обрабатывать аргументы командной строки из $ARGV как utf8, вам нужен другой подход. Один из способов — явный вызов Perl с флагом -C, установленным на A или 32 (это специальный параметр, который управляет кодировкой $ARGV) или, что то же самое, путем установки переменной среды PERL_UNICODE в терминале на A.

В качестве альтернативы вы можете перекодировать $ARGV из кода:

use Encode qw(decode_utf8);
@ARGV = map { decode_utf8($_, 1) } @ARGV;

В этом случае вам не нужен флаг командной строки.

Эта альтернатива также работает для замены обратных кавычек:

use Encode qw(decode_utf8);
my $unicode_string_backticks = decode_utf8(`cat unicode.string.txt`, 1);

Источник: https://www.perl.com/pub/2012/04/perlunicookbook-decode-argv-as-utf8.html/


Однако существует более простое решение, которое одновременно устанавливает utf8 для жестко закодированных строк, argv, файловых дескрипторов, printf, обратных кавычек и т. д., что является модулем utf8::all. При этом вам не нужны флаги командной строки или модуль Encode. Поскольку он нацелен на STDOUT, предупреждения о широких символах также разрешаются.

use utf8::all;
use Curses;

my $unicode_string_variable  = 'Ж 会 र';
my $unicode_string_argv      = $ARGV[0];
#my $unicode_string_backticks = decode_utf8(`cat unicode.string.txt`,1);
my $unicode_string_backticks = `cat unicode.string.txt`;
open my $open_pipe_read_handle, '-|:encoding(UTF-8)', 'cat', 'unicode.string.txt' || die;
my $unicode_string_open_pipe = <$open_pipe_read_handle>;

# print unicode to files
open my $hardcoded_handle, '>', 'unicode.string.hardcoded' || die;
  print $hardcoded_handle 'Ж 会 र';
  close $hardcoded_handle;
open my  $variable_handle, '>', 'unicode.string.variable'  || die;
  print  $variable_handle $unicode_string_variable;
  close  $variable_handle;
open my      $argv_handle, '>', 'unicode.string.argv'      || die;
  print      $argv_handle $unicode_string_argv;
  close      $argv_handle;
open my $backticks_handle, '>', 'unicode.string.backticks' || die;
  print $backticks_handle $unicode_string_backticks;
  close $backticks_handle;
open my $open_pipe_handle, '>', 'unicode.string.open_pipe' || die;
  print $open_pipe_handle $unicode_string_open_pipe;
  close $open_pipe_handle;

# print unicode to STDOUT
printf "%s: %s\n", 'hardcoded', 'Ж 会 र';
printf "%s: %s\n", 'variable ', $unicode_string_variable;
printf "%s: %s\n", 'argv     ', $unicode_string_argv;
printf "%s: %s\n", 'backticks', $unicode_string_backticks;
printf "%s: %s\n", 'open_pipe', $unicode_string_open_pipe;

initscr;

# print unicode to Curses
addstring 0, 0, 'hardcoded: ' . 'Ж 会 र';
addstring 1, 0, 'variable : ' . $unicode_string_variable;
addstring 2, 0, 'argv     : ' . $unicode_string_argv;
addstring 3, 0, 'backticks: ' . $unicode_string_backticks;
addstring 4, 0, 'open_pipe: ' . $unicode_string_open_pipe;

addstring 5, 0, 'Curses ' . Curses->VERSION . ", perl $^V" . ", OS: $^O";

getchar;
endwin;

Источник: https://blog.ostermiller.org/perl-wide-character-in-print/

Если по какой-либо причине вы не можете или не хотите устанавливать этот модуль, то use utf8; вместе с флагами командной строки -CSDA также решит все проблемы. Обратите внимание, что с этими флагами командной строки вы не должны использовать decode_utf8() в своем коде.

Полу-да. Этот данный фрагмент теперь работает правильно, но вместо addstring 0, 0, $ARGV[0]; ставите addstring 0, 0, 'Ж 会 र';, потом вызываете perl curses.unicode.pl 'Ж 会 र' и снова появляется мусор

uxer 07.01.2023 21:25

@uxer для этого использования perl -CA curses.unicode.pl 'Ж 会 र'.

Marijn 07.01.2023 21:32

Хорошо знать. Шаг вперед: мы получаем нашу юникодную строку через обратные кавычки или open. Последнее, кажется, нужно :encoding(UTF-8). Как исправить обратные кавычки? Зачем нужны 3 разных места — use utf8, -CA, :encoding(UTF-8) — чтобы включить один и тот же чертов юникод? Где единообразие? Почему это требуется только для Curses, а STDOUT и запись в файлы работают «из коробки»? Я также получаю ошибки Wide character in print... Я обновил вопрос

uxer 08.01.2023 00:04

@uxer смотрите изменения для версии с обратными кавычками и единого решения для всех проблем.

Marijn 08.01.2023 10:30

Другие вопросы по теме