Модераторы: korob2001, ginnie

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> unicode в perl 
:(
    Опции темы
slavenk
Дата 16.7.2012, 15:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


TheAthlete
*


Профиль
Группа: Участник
Сообщений: 69
Регистрация: 22.10.2009

Репутация: нет
Всего: нет



Здравствуйте!

Сейчас разбираюсь с юникодом в перл. У меня появилась такая проблема:

Код

my $bad_string_with_utf8_flag = "\x{d0}\x{90}";
say "utf8 flag: ".(utf8::is_utf8($bad_string_with_utf8_flag) ? 'is utf8' : 'no utf8');


Для данного кода должно выдать 

  utf8 flag: is utf8

а выдает:

  utf8 flag: no utf8

В чем может быть проблема? 

Пример писал по следующей статье: UTF Perl Practice, или как использовать UTF-8 в перле
PM MAIL ICQ Skype   Вверх
DurRandir
Дата 16.7.2012, 16:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 335
Регистрация: 27.9.2009

Репутация: 14
Всего: 17



Потому что вы записали в строку два байта. Перл "не догадывается", без вашей помощи, как эти байты интерпретировать) Чтобы строку из байт проинтерпретировать как строку, записанную в utf8, надо выполнить utf8::decode($bad_string_with_utf8_flag).
PM   Вверх
slavenk
Дата 16.7.2012, 16:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


TheAthlete
*


Профиль
Группа: Участник
Сообщений: 69
Регистрация: 22.10.2009

Репутация: нет
Всего: нет



Т.е. получается, в приведенной статье ошибка:

Цитата

utf8::is_utf8 проверяет состояние флага. возвращает 1 в том случае, если на строке установлен utf-флаг:

utf8::is_utf8("\x{410}") = 1
utf8::is_utf8("\x{d0}\x{90}") = 1 # здесь не 1, а 0 (или undef)
utf8::is_utf8('А') = undef

PM MAIL ICQ Skype   Вверх
DurRandir
Дата 16.7.2012, 16:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 335
Регистрация: 27.9.2009

Репутация: 14
Всего: 17



Напишите автору)
PM   Вверх
slavenk
Дата 16.7.2012, 16:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


TheAthlete
*


Профиль
Группа: Участник
Сообщений: 69
Регистрация: 22.10.2009

Репутация: нет
Всего: нет



Т.е. я так понял, что данная строка ("\x{d0}\x{90}") не имеет UTF-флага, UTF-флаг имеет каждый октет и чтобы Perl воспринимал данную строку как строку с UTF-флагом, нужно преобразовать ее в "нормальное" представление ("\x{410}") с помощью utf8::decode?
PM MAIL ICQ Skype   Вверх
slavenk
Дата 16.7.2012, 17:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


TheAthlete
*


Профиль
Группа: Участник
Сообщений: 69
Регистрация: 22.10.2009

Репутация: нет
Всего: нет



Что-то я запутался!

Например, мы имеем три переменные:
Код

my $string_with_utf8_flag = "\x{410}";
my $string_without_utf8_flag = "А";
my $bad_string_without_utf8_flag = "\x{d0}\x{90}";


Названия переменных говорят сами за себя, т.е.
"\x{410}" - это настоящая Unicode строка, при проверке на utf8::is_utf8 выдает true
"А" - строка без utf-флага, т.е. по-сути набор байтов
"\x{d0}\x{90}" - "поломанная" строка без utf-флага

Но вот незадача - Data::Dumper выводит для строки $bad_string_without_utf8_flag строку 'А', а не "\x{d0}\x{90}". А все потому, что строка не имеет utf-флага. Для того, чтобы поднять utf-флаг, необходимо выполнить:

Код

utf8::upgrade($bad_string_without_utf8_flag);


Самое интерестное, что если к строке $string_without_utf8_flag применить функцию utf8::upgrade, мы получим строку "\x{d0}\x{90}" с поднятым utf-флагом

Добавлено через 10 минут и 24 секунды
Из данных рассуждений получается следующее: чтобы вышеприведенные пример из статьи был правильным (корректным), необходимо вручную выставить utf-флаг на строку "\x{d0}\x{90}".

Другими словами, для данного кода
Код

my $string_with_utf8_flag = "\x{410}";
my $string_without_utf8_flag = "А";
my $bad_string_with_utf8_flag = "\x{d0}\x{90}";
utf8::upgrade($bad_string_with_utf8_flag);


данная статья будет корректна, и Data::Dumper будет нормально отображать строку "\x{d0}\x{90}", а utf8::is_utf8 будет давать 1 (true)


Это сообщение отредактировал(а) slavenk - 16.7.2012, 17:40
PM MAIL ICQ Skype   Вверх
Pfailed
Дата 16.7.2012, 18:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 933
Регистрация: 19.7.2009

Репутация: 22
Всего: 39



perlunicode
Цитата

you can use the "\x{...}" notation for characters 0x100 and above. For characters below 0x100 you may get byte semantics instead of character semantics; see "The "Unicode Bug"


В статье пишется, что это два символа юникод. На самом деле это два байта.


--------------------
PM MAIL   Вверх
slavenk
Дата 17.7.2012, 10:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


TheAthlete
*


Профиль
Группа: Участник
Сообщений: 69
Регистрация: 22.10.2009

Репутация: нет
Всего: нет



Действительно:

Цитата

utf8::encode($string) 

Converts in-place the character sequence to the corresponding octet sequence in UTF-X. That is, every (possibly wide) character gets replaced with a sequence of one or more characters that represent the individual UTF-X bytes of the character. The UTF8 flag is turned off. Returns nothing.
Код

    my $a = "\x{100}"; # $a contains one character, with ord 0x100
    utf8::encode($a);  # $a contains two characters, with ords 0xc4 and 0x80


Note that this function does not handle arbitrary encodings. Therefore Encode is recommended for the general purposes; see also Encode.
$success = utf8::decode($string) 

Attempts to convert in-place the octet sequence in UTF-X to the corresponding character sequence. That is, it replaces each sequence of characters in the string whose ords represent a valid UTF-X byte sequence, with the corresponding single character. The UTF-8 flag is turned on only if the source string contains multiple-byte UTF-X characters. If $string is invalid as UTF-X, returns false; otherwise returns true.
Код

    my $a = "\xc4\x80"; # $a contains two characters, with ords 0xc4 and 0x80
    utf8::decode($a);   # $a contains one character, with ord 0x100


Note that this function does not handle arbitrary encodings. Therefore Encode is recommended for the general purposes; see also Encode.


Единственно, не могу понять, как правильно перевести слово "ord" в комментарии
Код

# $a contains two characters, with ords 0xc4 and 0x80


PM MAIL ICQ Skype   Вверх
Pfailed
Дата 17.7.2012, 12:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 933
Регистрация: 19.7.2009

Репутация: 22
Всего: 39



По смыслу получается
Код

# $a содержит два символа, с кодами 0xc4 и 0x80

ords, видимо, образовано от функции ord(), или от слова, от которого образована функция ord().


Это сообщение отредактировал(а) Pfailed - 17.7.2012, 12:48


--------------------
PM MAIL   Вверх
DurRandir
Дата 17.7.2012, 13:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 335
Регистрация: 27.9.2009

Репутация: 14
Всего: 17



>слова, от которого образована функция ord
Ordinal smile
PM   Вверх
slavenk
Дата 17.7.2012, 13:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


TheAthlete
*


Профиль
Группа: Участник
Сообщений: 69
Регистрация: 22.10.2009

Репутация: нет
Всего: нет



Цитата(Pfailed @  16.7.2012,  18:01 Найти цитируемый пост)
В статье пишется, что это два символа юникод. На самом деле это два байта.

Кстати, это не два байта, а два слова (четыре байта (октета)). Это как раз доказывает функция utf8::upgrade:

$num_octets = utf8::upgrade('А'); # $num_octets = 4
PM MAIL ICQ Skype   Вверх
Pfailed
Дата 17.7.2012, 14:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 933
Регистрация: 19.7.2009

Репутация: 22
Всего: 39



Насколько я понял upgrade() говорит сколько байт нужно что бы представить переданную последовательность, как буквы в utf-8. По два байта на каждый non-ASCII символ, итого 4.
Попробуйте функцию length() на этой последовательности, она должна возвратить 2.



--------------------
PM MAIL   Вверх
DurRandir
Дата 17.7.2012, 15:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 335
Регистрация: 27.9.2009

Репутация: 14
Всего: 17



>По два байта на каждый non-ASCII символ
Вообще, для перлового понимания utf-8, это 2-13. Но для общепринятого юникода - 2-4.

А length на utf-8 строке вернёт её длину в символах, а не байтах. Ради чего всё и затевается. Чтобы посмотреть, что творится внутри строки, надо использовать Devel::Peek'овский Dump.

Код

#невероятно!
perl -E '$a="\x{fffffff0}"; utf8::upgrade($a); use Devel::Peek; Dump $a; say "length is ", length $a' 
SV = PV(0x601078) at 0x61a348
  REFCNT = 1
  FLAGS = (POK,pPOK,UTF8)
  PV = 0x6020e0 "\376\203\277\277\277\277\260"\0 [UTF8 "\x{fffffff0}"]
  CUR = 7
  LEN = 16
length is 1

#"валидный" юникод
perl -E 'use charnames qw/:full/; $a="\N{TETRAGRAM FOR FULLNESS}"; utf8::upgrade($a); use Devel::Peek; Dump $a; say "length is ", length $a' 
SV = PV(0x601078) at 0x61a408
  REFCNT = 1
  FLAGS = (POK,pPOK,UTF8)
  PV = 0x6020e0 "\360\235\214\253"\0 [UTF8 "\x{1d32b}"]
  CUR = 4
  LEN = 16
length is 1

#в utf-8 это будет 4 байта, но 2 символа
perl -E '$a="\x{c4}\x{80}"; utf8::upgrade($a); use Devel::Peek; Dump $a; say "length is ", length $a'
SV = PV(0x601078) at 0x61a348
  REFCNT = 1
  FLAGS = (POK,pPOK,UTF8)
  PV = 0x6020e0 "\303\204\302\200"\0 [UTF8 "\x{c4}\x{80}"]
  CUR = 4
  LEN = 16
length is 2

#а вот для ascii-строки число байт и символов совпадут
perl -E '$a="\x{c4}\x{80}"; use Devel::Peek; Dump $a; say "length is ", length $a'
SV = PV(0x601078) at 0x61a348
  REFCNT = 1
  FLAGS = (POK,pPOK)
  PV = 0x6020e0 "\304\200"\0
  CUR = 2
  LEN = 16
length is 2



Это сообщение отредактировал(а) DurRandir - 17.7.2012, 15:27
PM   Вверх
slavenk
Дата 17.7.2012, 15:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


TheAthlete
*


Профиль
Группа: Участник
Сообщений: 69
Регистрация: 22.10.2009

Репутация: нет
Всего: нет



Большое спасибо за код! Я так понял, только в последнем примере utf8-флаг не установлен. А CUR - это число байтов
PM MAIL ICQ Skype   Вверх
DurRandir
Дата 17.7.2012, 16:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 335
Регистрация: 27.9.2009

Репутация: 14
Всего: 17



>slavenk
Да
PM   Вверх
Pfailed
Дата 17.7.2012, 17:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 933
Регистрация: 19.7.2009

Репутация: 22
Всего: 39



Цитата(DurRandir @  17.7.2012,  15:23 Найти цитируемый пост)
А length на utf-8 строке вернёт её длину в символах, а не байтах. 

Обсуждаемая строка была не utf-8. Для того что бы убедиться можно сделать "use bytes"


--------------------
PM MAIL   Вверх
krypt3r
Дата 18.7.2012, 05:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 359
Регистрация: 9.6.2009

Репутация: 2
Всего: 16



PM MAIL   Вверх
slavenk
Дата 18.7.2012, 13:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


TheAthlete
*


Профиль
Группа: Участник
Сообщений: 69
Регистрация: 22.10.2009

Репутация: нет
Всего: нет



Спасибо за ссылки, кстати в первом посте я указал ссылку http://www.nestor.minsk.by/sr/2008/09/sr80902.html. 
Сейчас разбираюсь с Devel::Peek

Есть вот такой код:
Код

use Modern::Perl;
use Devel::Peek;

my $a = 'А';
say Dump $a;


На выход выдает следующее:
SV = PV(0x8d66b60) at 0x8d5c128
  REFCNT = 1
  FLAGS = (PADMY,POK,pPOK)
  PV = 0x8d4eb90 "\320\220"\0
  CUR = 2
  LEN = 12

Не могу понять, что из себя представляет код "\320\220". В какой это кодировке и как можно перевести обратно в нормальное представление?
PM MAIL ICQ Skype   Вверх
DurRandir
Дата 18.7.2012, 14:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 335
Регистрация: 27.9.2009

Репутация: 14
Всего: 17



>say Dump $a;
say не нужен, Dump уже печатает свой вывод

Эта просто байты представления "А" в utf8, т.к. сам скрипт (исходник) в utf-8 (записалось 2 байта за 1 символ в исходнике). Чтобы это стало действительно "А" и с ним можно было работать, существует 2 пути:
1) utf8::decode($a) - нужно, если такие строки приходят снаружи, от каких-либо внешних источников - к примеру, по сети передаются только байты, а как их интерпретировать - уже ваша задача.
2) use utf8; в начале программы. 

Это сообщение отредактировал(а) DurRandir - 18.7.2012, 14:34
PM   Вверх
slavenk
Дата 23.7.2012, 11:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


TheAthlete
*


Профиль
Группа: Участник
Сообщений: 69
Регистрация: 22.10.2009

Репутация: нет
Всего: нет



Здравствуйте!
Продолжаю разбираться с unicode в Perl. Теперь не пойму следующее: для чего можно применить подпрагмы IN и OUT прагмы open, например

Код

use open IN  => ":crlf", OUT => ":bytes";


Как я понял, это больше подходит для файлов, чем для стандартных потоков ввода вывода - STDIN, STDOUT и STDERR, но пример не могу составить, как работают эти подпрагмы.
PM MAIL ICQ Skype   Вверх
krypt3r
Дата 24.7.2012, 06:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 359
Регистрация: 9.6.2009

Репутация: 2
Всего: 16



Цитата
With the "IN" subpragma you can declare the default layers of input streams, and with the "OUT" subpragma you can declare the default layers of output streams.  With the "IO"  subpragma you can control both input and output streams simultaneously.

PM MAIL   Вверх
Страницы: (2) [Все] 1 2 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Perl"
korob2001
sharq
  • В этом разделе обсуждаются общие вопросы по языку Perl
  • Если ваш вопрос относится к системному программированию, задавайте его здесь
  • Если ваш вопрос относится к CGI программированию, задавайте его здесь
  • Интерпретатор Perl можно скачать здесь ActiveState, O'REILLY, The source for Perl
  • Справочное руководство "Установка perl-модулей", можно скачать здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, korob2001, sharq.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Perl: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0938 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.