如何在Perl v5.24中获取unicode代码点?

时间:2019-05-21 16:17:13

标签: perl unicode ord

我想记录被剪切并粘贴到bash中作为参数的字符串的十六进制unicode代码点。 ord不这样做; ord似乎只能在ascii范围内使用。

我发现的关于ord的大多数内容都至少六岁或更老,并且不再相关,因为我正在阅读的v5.24内置了Unicode支持。 在python中这很简单:


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

从bash开始工作。 我认为问题出在ord函数本身,而unicode似乎没有更新。


# 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 个答案:

答案 0 :(得分:4)

这不是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";
}

但是,您的python脚本所做的事情却大不相同,它返回的是编码为UTF-16BE的字符串的十六进制表示,而不是Unicode字符的十进制序数。您也可以在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";
}

答案 1 :(得分:3)

相当于

的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", $_)