Решено: Perl, regexp, Unicode (кириллица не опознается в POSIX-классах)

Модератор: Модераторы разделов

VladimirP
Сообщения: 164

Решено: Perl, regexp, Unicode

Сообщение VladimirP »

Вот такой фрагмент программы на Перле:

Код: Выделить всё

use strict;
## use utf8;
use locale;

my $RE = '^([[:graph:]]+)';

while ( $STR = <> )
{
    chomp( $STR );
    print "-$STR\n";
    my $matches = ( $STR =~ m/$RE/ );
    print $matches ? "matches\n" : "not matches\n";
}


Когда на вход подается латиница, всё работает правильно. Но если есть кирилица в utf-8, регулярное выражение не узнаёт графические символы.

Пробовал включать прагму "use utf8", use POSIX qw(locale_h), setlocale( LC_ALL, "" ), setlocale( LC_ALL, "ru_RU.UTF-8" ), -- всё это в различных комбинациях. Не помогает.

Работает выражение $RE = '^(\p{IsGraph}+)'. Но документация говорит, что "use locale" должно заставлять Perl работать в текущей локали, и POSIX-классы должны пониматься.

Что не верно в моём фрагменте?
Системная локаль ru_RU.UTF-8, LC_ALL="".
Спасибо сказали:
sergio
Сообщения: 436
Статус: Интересующийся новичок
ОС: Debian GNU/Linux 4 & 5

Re: Решено: Perl, regexp, Unicode

Сообщение sergio »

VladimirP писал(а):
17.10.2007 15:08
Что не верно в моём фрагменте?
Системная локаль ru_RU.UTF-8, LC_ALL="".


Хе-хе, нас уже двое. :)

У меня самый рабочий вариант был такой:

# use locale ;
use encoding 'utf8' ;
# use utf8 ;

В регекспах (я перловые пользую, позикс не пробовал) матч работал вроде окей, замена НЕ работала с русским.
С проблемой не разбирался, по верхам в документацию потыкался, вот это нашел и пока больше не копал.
С удовольствием послушаю того, кто знает тайну золотого ключика. :happy:
Debian GNU/Linux 4 -- AMD Athlon64 3000+ / Asus 7600GS -- Gnome
Debian GNU/Linux 5 -- Dell (Vostro) 500 (Celeron M560 / iGM965) -- Gnome
Спасибо сказали:
VladimirP
Сообщения: 164

Re: Решено: Perl, regexp, Unicode

Сообщение VladimirP »

Самое неприятное, что поиск в Google не нашел ничего подходящего. Можно, конечно, заменить все символьные классы с POSIX на Unicode prorerties, но я не хочу жестко завязываться на Unicode. Лучше, если на вход будет подан текст в кодировке, совпадающей с системной локалью, и чтоб Perl правильно его распознал.
Спасибо сказали:
Аватара пользователя
sash-kan
Администратор
Сообщения: 13939
Статус: oel ngati kameie
ОС: GNU

Re: Решено: Perl, regexp, Unicode

Сообщение sash-kan »

Код: Выделить всё

$ echo "some тест" | perl -p0e 's/[[:graph:]]/b/g'
bbbb тест
$ echo "some тест" | perl -C -p0e 's/[[:graph:]]/b/g'
bbbb bbbb
Писать безграмотно - значит посягать на время людей, к которым мы адресуемся, а потому совершенно недопустимо в правильно организованном обществе. © Щерба Л. В., 1957
при сбоях форума см.блог
Спасибо сказали:
VladimirP
Сообщения: 164

Re: Решено: Perl, regexp, Unicode

Сообщение VladimirP »

Решение найдено после прочтения статьи: http://xpoint.ru/know-how/Perl/PodderzhkaUnicode?24
Помогла прагма use open ':locale'; в начале скрипта.

Прагма open - это вспогательный интерфейс для определения "уровеней" по умолчанию для всех потоков ввода/вывода. В любых двух-аргументных вызовах open(), readpipe() (он же qx//) и в подобных операторах, находящихся в пределах лексической области видимости этой прагмы, будут использованы указанные значения по умолчанию.
[...]
Если вы хотите чтобы кодировки были выбраны автоматически в соответствии с установленной в системе локалью, то используйте :locale
Спасибо сказали:
sergio
Сообщения: 436
Статус: Интересующийся новичок
ОС: Debian GNU/Linux 4 & 5

Re: Решено: Perl, regexp, Unicode

Сообщение sergio »

VladimirP писал(а):
18.10.2007 14:04
Решение найдено после прочтения статьи:

Вау, и вправду заработало. Если переменные определены в скрипте то и так работает вроде, а при чтении из файла нихрена. :unsure:
Что же там, мама, куча "типов строк" и с каждой строкой копируется ее "тип" что ли?? Пшел читать статью. Спасибо.
Debian GNU/Linux 4 -- AMD Athlon64 3000+ / Asus 7600GS -- Gnome
Debian GNU/Linux 5 -- Dell (Vostro) 500 (Celeron M560 / iGM965) -- Gnome
Спасибо сказали:
VladimirP
Сообщения: 164

Re: Решено: Perl, regexp, Unicode

Сообщение VladimirP »

Тип строк там один, и строки внутри хранятся в UTF-8. Здесь наша ошибка оказалась в работе не с памятью, а с данными в файле. Без прагмы Перл не знал, что он читает данные в кодировке UTF, и операция чтения искажала данные. Прагмой мы ему скомандовали: читая данные из файла считать, что кодировка соответствует системной локали. Теперь он знает, как правильно перекодировать данные во внутреннюю кодировку, в память попадают правильные данные, и распознавание шаблонов работает верно.
Спасибо сказали:
sergio
Сообщения: 436
Статус: Интересующийся новичок
ОС: Debian GNU/Linux 4 & 5

Re: Решено: Perl, regexp, Unicode

Сообщение sergio »

VladimirP писал(а):
19.10.2007 08:00
Без прагмы Перл не знал, что он читает данные в кодировке UTF, и операция чтения искажала данные. Прагмой мы ему скомандовали: читая данные из файла считать, что кодировка соответствует системной локали. Теперь он знает, как правильно перекодировать данные во внутреннюю кодировку, в память попадают правильные данные, и распознавание шаблонов работает верно.

Боюсь что не-а. Данные он не искажал - у меня, по крайней мере - и замечательно писал их потом обратно и все было тип-топ. Т.е. работал с ними как с обычной однобайтной кодировкой. Там в статье в общем-то расписано вполне, только сумбурно, да и сама эта дурь в перле тоже хороша. Там, если заметили, было упоминание, что в 5.8.0 что ли, при включении use locale он начинал читать данные из файлов в ЮТФ, если локаль была ЮТФ, но потом это отключили, для сохранения работоспособности старого кода, и теперь при включении локали, если локаль ютф он считывая данные из файла в строку вешает на строку маркер НЕ_ютф. Если не принять специальных мер - открывать файлы с доп.флагом, или указывать прагму use open.
А тип строк по-существу разный, поскольку в зависимости от маркера кодировки для них вызываются разные версии одних и тех же стандартных функций, и ютф-ориентированные из них соответственно выделяют из последовательности ютф-символы и т.д., регекспы как раз из таких. В том и была наша проблема.
Debian GNU/Linux 4 -- AMD Athlon64 3000+ / Asus 7600GS -- Gnome
Debian GNU/Linux 5 -- Dell (Vostro) 500 (Celeron M560 / iGM965) -- Gnome
Спасибо сказали: