?

Log in

No account? Create an account
интересно только программистам - Поклонник деепричастий [entries|archive|friends|userinfo]
Anatoly Vorobey

[ website | Website ]
[ userinfo | livejournal userinfo ]
[ archive | journal archive ]

Links
[Links:| English-language weblog ]

интересно только программистам [окт. 8, 2006|11:01 pm]
Anatoly Vorobey

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

Баг в функции sprintf. Он проявляется, когда при выводе строки (аргумент %s), которая к тому же содержит широкие символы в UTF-8 (напр. русские буквы), используются одновременно оба ограничения на длину - минимальное и максимальное - и они равны. Ниже копирую вывод моей тест-программы, которая изолирует баг, и демонстрирует, при каких вызовах функции он происходит.

Первые две пары вызовов printf демонстрируют баг, остальные - его отсутствие при других аргументах.

printf('%-3.3s', 'абвгд'): |абв  |
printf('%-3.3s', '01234'): |012|

printf('%3.3s', 'абвгд'): |  абв|
printf('%3.3s', '01234'): |012|

printf('%3s', 'абвгд'): |абвгд|
printf('%3s', '01234'): |01234|

printf('%.3s', 'абвгд'): |абв|
printf('%.3s', '01234'): |012|

printf('%3.4s', 'абвгд'): |абвг|
printf('%3.4s', '01234'): |0123|

Проверил, что баг содержится и в самой последней версии языка. Теперь надо посмотреть, сколько осталось пороха в пороховницах и насколько будет легко его починить...

СсылкаОтветить

Comments:
[User Picture]From: b_a_t
2006-10-08 09:11 pm
Как ведет себя данный код при use locale; и при use utf8; ?

Не может ли это быть ошибкой libc?
(Ответить) (Thread)
[User Picture]From: avva
2006-10-08 09:17 pm
Подразумевается use utf8; (поэтому я могу вставлять строку прямо в текст программы). use locale; тут вообще не должно играть роли. С точки зрения Перла (при наличии use utf8;) строки "абвгд" и "01234" одинаковой длины, 5 символов, и все указания длин внутри форматной строки sprintf относятся к символам, а не к байтам (и в принципе это работает, как видно из тех примеров, где баг не происходит).

Это точно не ошибка libc, sprintf перла не пользуется sprintf'ом системы, вместо этого все делает сам внутри.
(Ответить) (Parent) (Thread) (Развернуть)
[User Picture]From: ninazino
2006-10-08 09:53 pm
Хм. В моей версии нет проблемы. Следующий код:

print "_"; printf('%-3.3s', 'abcde');print "_\n";
print "_"; printf('%-3.3s', '01234');print "_\n";
print "_"; printf('%3.3s', 'abcde');print "_\n";
print "_"; printf('%3.3s', '01234');print "_\n";

Печатает(ожидаемо):
_abc_
_012_
_abc_
_012_


А следующий код:
print "_"; printf '<%.5s>', "truncated"; print "_\n";
print "_"; printf '<%.5s>', "012345678"; print "_\n\n;

print "_"; printf '<%10.5s>', "truncated"; print "_\n";
print "_"; printf '<%10.5s>', "012345678"; print "_\n\n";

print "_"; printf '<%-.5s>', "truncated"; print "_\n";
print "_"; printf '<%-.5s>', "012345678"; print "_\n\n";

print "_"; printf '<%-10.5s>', "truncated"; print "_\n";
print "_"; printf '<%-10.5s>', "012345678"; print "_\n\n";

Печатает (тоже ожидаемо):
__
_<01234>_

_< trunc>_
_< 01234>_

__
_<01234>_

__
_<01234 >_

А какая у Вас версия версия perl? У меня v5.8.4
(Ответить) (Thread)
From: 9000
2006-10-08 10:25 pm
А где тут символы с кодом более 255? %)
Попробуйте русские буквы (начинаются с 0x410), расширенную латиницу (от 0x100), греческие (0x391), etc.
(Ответить) (Parent) (Thread) (Развернуть)
[User Picture]From: avva
2006-10-08 11:09 pm
Вроде бы починил.

--- perl-5.9.4-orig/sv.c        2006-08-15 15:37:41.000000000 +0300
+++ perl-5.9.4/sv.c     2006-10-09 01:06:31.000000000 +0200
@@ -8874,6 +8874,8 @@
                    }
                    if (width) { /* fudge width (can't fudge elen) */
                        width += elen - sv_len_utf8(argsv);
+                       if (has_precis && precis < elen)
+                           width += precis - elen;
                    }
                    is_utf8 = TRUE;
                }


Теперь послать им еще наверное неплохо бы.
(Ответить) (Thread)
[User Picture]From: avva
2006-10-08 11:43 pm
Нет, это не совсем верно. Надо еще кое-что подкрутить.
(Ответить) (Parent) (Thread) (Развернуть)
[User Picture]From: smilga
2006-10-09 01:13 am
У меня куда серьёзней проблема вылезла в субботу. Представьте себе, что нужно прочитать файл, кодированный в utf-8, это, например, open(IN, "<:encoding(utf-8)", $FILE) or die; while(<IN>) { ... }. Если в файле при этом испорченный utf (что в Сети встречается гораздо чаще, чем следовало бы), то 5.8.6-й перл может при чтении ошибочной строки свалиться в бесконечный цикл, печатая всё время utf8 "..." does not map to Unicode. Я пока не разобрался, исправлено ли это в более свежих версиях.
(Ответить) (Thread)
[User Picture]From: avva
2006-10-09 01:18 am
Какая прелесть!

Видимо, читайте весь файл в память в байтах и переводите через Encode после чтения (или построчно).
(Ответить) (Parent) (Thread) (Развернуть)
[User Picture]From: serejik
2006-10-09 03:03 am
О господи. :-)) 7 последних лет пишу на перле, всегда обхожусь минимумом доступого синтаксиса, всю обработку строк, в том числе и в разных локалях делаю ручками, как будто в языке ничего кроме побайтовой выборки из строки нет.

Прямо америку открыли для меня, честно. Занятно...
(Ответить) (Thread)
[User Picture]From: aburachil
2006-10-09 08:44 am

Ругательство при использовании юникода

А вот скажите, Анатолий, может быть Вы знаете ответ на вопрос, который меня давно занимает --- если я говорю что-то вроде

use charnames ':full';print "\x{0041}\N{WHITE SMILING FACE}"



то получаю на выходе букву А и смайлик, что вполне понятно, но кроме того, пёрл говорит "Wide character in print". Вот вопрос собственно такой --- зачем он это говорит, наверное что-то я не так делаю, но не понимаю, что именно?
(Ответить) (Thread)
[User Picture]From: avva
2006-10-09 08:53 am

Re: Ругательство при использовании юникода

Да, надо сделать binmode STDOUT, ":utf8"; чтобы он не боялся посылать юникодные символы в данный поток вывода. С точки зрения самого потока ничего не изменится, те же utf8-байты. Если писать в файл, то можно его сразу открывать чем-то вроде open OUT, ">:utf8", "filename".
(Ответить) (Parent) (Thread) (Развернуть)
[User Picture]From: egorfine
2006-10-09 11:00 am
перл и ютф8 - какая боль, какая боль. :(
(Ответить) (Thread)
[User Picture]From: avva
2006-10-09 11:31 am
Уже не очень - начиная с 5.8.
(Ответить) (Parent) (Thread) (Развернуть)
From: (Anonymous)
2006-10-09 05:46 pm
Простите, милый Авва, что не в дугу, но все же выбрала спросить вас,т.к. вы всегда вежливы и все знаете к тому ж.
Я тут тоже размечталась открыть журнал - но кто дает? В смысле я для начала хочу фрее попробовать, а мне в ответ - сначала заплатите.
А я в кантри три тысячи заплатила и ни разу не пошла.
Может фрее акоунт отменинили? И где взять мануал на все действия - открытие и последующая эксплуатация.
Тут есть ваш мобильник - но это я думаю уже слишком?
сто раз спасибо и извините.
Ирина
i_risha7@hotmail.com
(Ответить) (Thread)
[User Picture]From: avva
2006-10-09 05:55 pm
https://www.livejournal.com/create.bml

Никто не отменял бесплатные аккаунты, попробуйте еще раз.

http://www.livejournal.com/manage/settings/

здесь вы можете выбрать русский язык просмотра и потом читать FAQ сайта: http://www.livejournal.com/support/faq.bml
(Ответить) (Parent) (Thread)