Преобразование символов Юникода в Perl?
Я хочу преобразовать текст (хинди) в Юникод на Perl. Я искал в CPAN. Но, я не мог найти точный модуль / путь, который я ищу. В принципе, я ищу что-то вроде этого.
Мои входные данные:
इस परीक्षण के लिए है
Мой ожидаемый результат:
u0907u0938u0020u092au0930u0940u0915u094du0937u0923u0020u0915u0947u0020u0932u093fu090fu0020u0939u0948
Как достичь этого в Perl?
Дайте мне несколько советов.
4 ответа:
Попробуйте это
use utf8; my $str = 'इस परीक्षण के लिए है'; for my $c (split //, $str) { printf("\\u%04x", ord($c)); } print "\n";
Вам действительно не нужен никакой модуль, чтобы сделать это.
ord
для извлечения кода char иprintf
для форматирования его в виде 4-х чисел нулевого дополненного шестнадцатеричного кода более чем достаточно:use utf8; my $str = 'इस परीक्षण के लिए है'; (my $u_encoded = $str) =~ s/(.)/sprintf "\\u%04x", ord($1)/sge; # \u0907\u0938\u0020\u092a\u0930\u0940\u0915\u094d\u0937\u0923\u0020\u0915\u0947\u0020\u0932\u093f\u090f\u0020\u0939\u0948
Если вы хотите только простой конвертер, вы можете использовать следующий фильтр
perl -CSDA -nle 'printf "\\u%*v04x\n", "\\u",$_' #or perl -CSDA -nlE 'printf "\\u%04x",$_ for unpack "U*"'
Как:
echo "इस परीक्षण के लिए है" | perl -CSDA -ne 'printf "\\u%*v04x\n", "\\u",$_' #or perl -CSDA -ne 'printf "\\u%*v04x\n", "\\u",$_' <<< "इस परीक्षण के लिए है"
Отпечатки пальцев:
\u0907\u0938\u0020\u092a\u0930\u0940\u0915\u094d\u0937\u0923\u0020\u0915\u0947\u0020\u0932\u093f\u090f\u0020\u0939\u0948\u000a
Unicode с суррогатными парами.
use strict; use warnings; use utf8; use open qw(:std :utf8); my $str = "if( \N{U+1F42A}+\N{U+1F410} == \N{U+1F41B} ){ \N{U+1F602} = \N{U+1F52B} } # ορισμός "; print "$str\n"; for my $ch (unpack "U*", $str) { if( $ch > 0xffff ) { my $h = ($ch - 0x10000) / 0x400 + 0xD800; my $l = ($ch - 0x10000) % 0x400 + 0xDC00; printf "\\u%04x\\u%04x", $h, $l; } else { printf "\\u%04x", $ch; } } print "\n";
Отпечатки
if( + == ){ = } # ορισμός \u0069\u0066\u0028\u0020\ud83d\udc2a\u002b\ud83d\udc10\u0020\u003d\u003d\u0020\ud83d\udc1b\u0020\u0029\u007b\u0020\ud83d\ude02\u0020\u003d\u0020\ud83d\udd2b\u0020\u007d\u0020\u0023\u0020\u03bf\u03c1\u03b9\u03c3\u03bc\u03cc\u03c2\u0020
Поскольку я оставил несколько комментариев о том, как другие ответы могут не соответствовать ожиданиям различных инструментов, я хотел бы поделиться решением, которое кодирует символы вне базовой многоязычной плоскости как пары двух эскейпов:
""
станет\ud83d\ude03
.Это делается с помощью:
Кодирование строки как UTF-16, без указания порядка байтов. Мы явно выбираем эндианесс. Здесь мы произвольно используем форму большого конца. Это создает строку октетов ("байт"), где два октета образуют одну кодовую единицу UTF-16, а два или четырех октетов представляют собой кодовую точку Юникода.
Это сделано для удобства и производительности; мы могли бы также определить числовые значения кодовых единиц UTF-16 самостоятельно.
unpack
Преобразуя полученную двоичную строку в 16-битные целые числа, представляющие каждый кодовый блок UTF-16. Мы должны уважать правильную конечность, поэтому мы используем шаблонn*
дляunpack
(т. е. 16-битный большой эндиан без знака целое число).Форматирование каждой единицы кода как
\uxxxx
escape.В качестве подпрограммы Perl это будет выглядеть как
use strict; use warnings; use Encode (); sub unicode_escape { my ($str) = @_; my $UTF_16BE_octets = Encode::encode("UTF-16BE", $str); my @code_units = unpack "n*", $UTF_16BE_octets; return join '', map { sprintf "\\u%04x", $_ } @code_units; }
Тестовые случаи:
use Test::More tests => 3; use utf8; is unicode_escpape(''), '', 'empty string is empty string'; is unicode_escape("\N{SMILING FACE WITH OPEN MOUTH}"), '\ud83d\ude03', 'non-BMP code points are escaped as surrogate halves'; my $input = 'इस परीक्षण के लिए है'; my $output = '\u0907\u0938\u0020\u092a\u0930\u0940\u0915\u094d\u0937\u0923\u0020\u0915\u0947\u0020\u0932\u093f\u090f\u0020\u0939\u0948'; is unicode_escape($input), $output, 'ordinary BMP code points each have a single escape';