Как получить код Unicode в Perl v5.24? - PullRequest
4 голосов
/ 21 мая 2019

Я хочу задокументировать шестнадцатеричные кодовые точки Юникода для строк, которые вырезаны и вставлены в bash в качестве аргумента. орд не делает этого; Похоже, что ord работает только в рамках ascii.

Большая часть того, что я нашел в отношении ord, имеет возраст не менее шести лет и больше не имеет отношения к делу, поскольку я использую v5.24, который, как я прочитал, имеет встроенную поддержку юникода. В питоне это тривиально:


for i in unicode(sys.argv[1], 'utf-8'):
    print i.encode("utf_16_be").encode("hex")

, который работает от Bash. Я думаю, что проблема в самой функции ord, которая не обновляется для юникода.


# ord.pl does not provide the unicode code point for a pasted variable.
use strict;
use warnings;
#use charnames (); #nope.
#use feature 'unicode_strings'; #nope.  Already automatically using as of v5.12.
#use utf8; #nope.
#binmode(STDOUT, ":encoding(UTF-8)"); #nope.

my $arg = "";

foreach $arg  (@ARGV) {
  print $arg . " is " . ord($arg) . " in code.\n";  # seems to me ord is ascii only.
  #utf8::encode($arg);  #nope.
  #print unpack("H*", $arg) . "\n";  #nope.

  #printf "%vX\n", $arg;  #nope.
}

, который получает:

david@A8DT01:~/bin$ ord.pl A B C D a b c d \  \\ … —  €
A is 65 in code.
41
B is 66 in code.
42
C is 67 in code.
43
D is 68 in code.
44
a is 97 in code.
61
b is 98 in code.
62
c is 99 in code.
63
d is 100 in code.
64
  is 32 in code.
20
\ is 92 in code.
5c
… is 226 in code.
c3a2c280c2a6
— is 226 in code.
c3a2c280c294
 is 239 in code.
c3afc280c2a8
€ is 226 in code.
c3a2c282c2ac
david@A8DT01:~/bin$

Я хотел бы получить вывод, полученный в python:

david@A8DT01:~/bin$ python code-points.py "ABCDabcd \ … —  €"
0041
0042
0043
0044
0061
0062
0063
0064
0020
005c
0020
2026
0020
2014
0020
f028
0020
20ac
david@A8DT01:~/bin$

Ответы [ 2 ]

4 голосов
/ 21 мая 2019

Это не проблема с ord, а с кодировкой.Ввод из командной строки, как правило, кодируется в кодировке UTF-8, и ord принимает только один символ, а не многобайтовую строку.Вы можете использовать переключатель -CA для автоматического декодирования @ARGV (или -CSA, чтобы STDOUT также кодировался для терминала), или сделать это в скрипте.

use strict;
use warnings;
use Encode;
foreach my $arg (@ARGV) {
  my $decoded = decode 'UTF-8', $arg;
  print $arg . " is " . ord($decoded) . " in code.\n";
}

Однако ваш питонскрипт делает что-то совсем другое, он возвращает шестнадцатеричное представление строки, закодированной в UTF-16BE, а не десятичные ординалы символов юникода.Вы можете сделать это также в Perl.

use strict;
use warnings;
use Encode;
foreach my $arg (@ARGV) {
  my $utf16 = encode 'UTF-16BE', decode 'UTF-8', $arg;
  print $arg . " is " . sprintf("%vX", $utf16) . " in code.\n";
}
3 голосов
/ 21 мая 2019

Perl-эквивалент

for ucp_str in unicode(sys.argv[1], 'utf-8'):
    print ucp_str.encode("utf_16_be").encode("hex")

равен

use Encode qw( decode encode );

for my $ucp_str (split(//, decode("UTF-8", $ARGV[0]))) {
   say unpack("H*", encode("UTF-16be", $ucp_str));
}

Демонстрация:

$ ./a.py aé€♠?
0061
00e9
20ac
2660
d840dc00

$ ./a.pl aé€♠?
0061
00e9
20ac
2660
d840dc00

Но вы попросили вывести кодовые точки, и это не то, чтоэти программы делают.Для этого вы можете использовать следующее:

use Encode qw( decode_utf8 );

for my $ucp_num (unpack('W*', decode_utf8($ARGV[0]))) {
   say sprintf("%04X", $ucp_num);
}

Демо:

$ ./a2.pl aé€♠?
0061
00E9
20AC
2660
20000

Чтобы получить символы строки в виде строк:

  • unpack('(a)*', $_)
  • split(//, $_)

Чтобы получить символы строки в виде чисел:

  • unpack('W*', $_)
  • map { ord($_) } split(//, $_))

Чтобы преобразовать строку байтов (символов в диапазоне 0x00..0xFF) в шестнадцатеричный код:

  • unpack('H*', $_)
  • join "", map { sprintf('%02X', $_) } split(//, $_))

Простой способ увидеть символы строки в шестнадцатеричном виде для отладки:

  • sprintf("%vX", $_)
...