LINUX.ORG.RU

Про Free Pascal Compiler и юникод в GNU/Linux'е

 , ,


1

4

Здравствуйте, любители юникода.

Довольно часто в обсуждениях мне приходилось видеть утверждение, что надо пользоваться языками программирования с встроенной поддержкой юникода. В пример приводился, например, Rust.

Однако, Rust слишком моден и молодёжен. Хочется чего-то более проверенного временем. И решил я тут посмотреть как с поддержкой юникода у Free Pascal Compiler'а. То, что эта поддержка есть, было видно по документации, но по всей этой документации, статьям, сообщениям на форумах и практической работе складывалось впечатление, что эта поддержка только поверхностна, и всё равно придётся работать с отдельными байтами. Вероятно, многие кто с этим сталкивался думают также. Однако, решение есть! Чтобы его откопать мне пришлось много всего перелопатить, но я его нашёл.

program strutftest;
    {$codepage UTF8}
    uses cwstring;
var
        s1: UnicodeString;
        s2: UnicodeString;
begin
  s1 := 'линуксоиды';
  s2 := Copy(s1, 1, 6);
  writeln(s2);
  s2 := 'т' + Copy(s1, 4, 3);
  writeln(s2);
  s2 := UTF8String(#$CE#$B1#$CE#$B2#$CE#$B3#$CE#$B4);
  writeln(s2);
  writeln(pos('ксоид', s1));
  s2 := Copy(s1, 1, 6);
  delete(s1, 1, 6);
  insert('гуман', s1, 1);
  insert(' тоже любят ', s1, 10);
  insert(s2, s1, 22);
  writeln(s1);
end.
Компилируем, запускаем:
$ ./strutftest
линукс
тукс
αβγδ
5
гуманоиды тоже любят линукс
Как видно, строки
    {$codepage UTF8}
    uses cwstring;
в начале исходника включают в FPC юникод во все поля, и стандартные функции Паскаля для работы со строками начинают работать именно с юникодом, а не с отдельными байтами.

★★★★★

Ответ на: комментарий от Virtuos86

Что можно работать с юникодными строками в Паскале.

Мне пришлось час гуглить и экспериментировать чтобы выяснить этот вопрос.

saahriktu ★★★★★ ()
Последнее исправление: saahriktu (всего исправлений: 1)
Ответ на: комментарий от dikiy

Да. В том же Си работа с юникодом по-настоящему начинается, как минимум, с нового модного и молодёжного типа wchar_t для работы с которым ввели новые модные и молодёжные функции. Прежние строковые функции так и остались однобайтными и работают только с типом char, подразумевая, что символ равен байту и наоборот.

И тот же Free Pascal Compiler по дефолту тоже перебирает отдельные байты. И нужно ещё уметь включать в нём юникод. И я, вот, нашёл как это делается.

saahriktu ★★★★★ ()
Ответ на: комментарий от grem

Просто тип ничего не даёт. Убираем те 2 строки в которых вся суть и видим, что теперь «символ == байт»:

$ ./strutftest
лин
т¸н
αβγδ
9
гума� тоже ллинюбят ½уксоиды

saahriktu ★★★★★ ()
Последнее исправление: saahriktu (всего исправлений: 1)

Только нужно помнить, что элементы UnicodeString — это WideChar, который, в свою очередь,

type
  WideChar = #$0000..#$FFFF

То есть, добро пожаловать в UTF-16 со всеми его прелестями ;-)
В том числе, не избавлены от суррогатных пар, и один символ может состоять из нескольких WideChar, несмотря на то, что в примере на это просто «забили» ;-)

bormant ★★★★★ ()
Ответ на: комментарий от grem

Нет, в итоге помогла эта статья: http://www.freepascal.ru/article/freepascal/20120718142000/

Только там я нашёл как правильно пользоваться UnicodeString. До этого я видел именно

лин
т¸н
αβγδ
9
гума� тоже ллинюбят ½уксоиды
вместо
линукс
тукс
αβγδ
5
гуманоиды тоже любят линукс

saahriktu ★★★★★ ()
Ответ на: комментарий от saahriktu

Что можно работать с юникодными строками в Паскале.

Мне пришлось час гуглить и экспериментировать чтобы выяснить этот вопрос.

То есть бложик. Хотя забавно узнать, что в современном паскале юникод надо дополнительно подключать.

Virtuos86 ★★★★★ ()
Ответ на: комментарий от Virtuos86

Бложик он же ЖЖ на техническом ресурсе - это когда нетехническая информация из личной жизни. Например: «Сегодня на улице дождь. Сходил в магазин и купил там кефир. На обед была гречка.».

А техническая информация - это техническая информация. Это как стандартная тема с вопросом, только наоборот. Я мог бы написать альфа вариант сабжевой программы, увидеть что она не работает как нужно, прийти сюда на ЛОР и спросить что с этим делать дальше. И мне бы отвечали. А после решения вопросов темы не удаляют для того, чтобы они пригодились другим людям с такими же самымм вопросами. Соответственно, если сразу выложить решение, то такая тема, по сути, ничем не отличается от тех, где изначально решения не было. И те и другие темы - сборники решений. Поэтому и говорят тем, кто открывает темы с вопросами: «Если решите вопрос сами, то не забудьте поделиться решением с остальными».

saahriktu ★★★★★ ()

{$codepage UTF8}

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

Napilnik ★★★★★ ()
Ответ на: комментарий от Virtuos86

Хотя забавно узнать, что в современном паскале юникод надо дополнительно подключать.

А ты хотел чтобы порча данных происходила по умолчанию? Например, положил ты в строки НЕХ, перекинул её через несколько функций и система твои данные конвертировала и запортила всё что не вписалось в стандарт? Это тебе не жаба, в паскале в ansistring можно бинарный файл загрузить, а потом использовать для таких строк штатные функции для их обработки. Здесь такое можно, а если тебе нужны перекодирования без твоего участия, то ты должен дать на это согласие и указать используемые кодировки.

Napilnik ★★★★★ ()
Ответ на: комментарий от Napilnik

Хотя забавно узнать, что в современном паскале юникод надо дополнительно подключать.

А ты хотел чтобы порча данных происходила по умолчанию?

Не в курсе, как с такой проблемой справляются ЯП, в которых строки по умолчанию юникодные?

Это тебе не жаба, в паскале в ansistring можно бинарный файл загрузить
ansistring

Это прекрасно. Не знаю, как в Java, но в питоне, например, для бинарных данных есть отдельный тип байтовых строк. И обычно ты знаешь, с чем имеешь дело, а не

положил ты в строки НЕХ, перекинул её через несколько функций и система твои данные конвертировала и запортила всё что не вписалось в стандарт

ССЗБ

Virtuos86 ★★★★★ ()

Однако, Rust слишком моден и молодёжен. Хочется чего-то более проверенного временем. И решил я тут посмотреть как с поддержкой юникода у Free Pascal Compiler'а.

Free Pascal проверен временем в том смысле, что все виды Pascal устарели и могут быть нужны только тому, кто когда-то давно выучил какой-то Pascal и больше не хочет учиться.

Поддержка Unicode есть не только в Rust, но и во всех актуальных языках. Так, в Java и в C++ (в популярных компиляторах), внутреннее представление строк - UTF-16, но при вводе-выводе текста рекомендуеттся использовать UTF-8. UTF-8 вообще наиболее универсальная кодировка, годится для всех разговорных языков и для всех операционных систем. Поэтому её и надо по возможности использовать для текстов.

Хотя я пока не стал бы относить Rust к основным современным языкам программирования, но его популярность растёт. Он не молодёжный, а просто современный. Это тот, кто пользуется Pascal устарел, независимо от возраста.

Partisan ★★ ()
Ответ на: комментарий от Partisan

все виды Pascal устарели

Это молодёжная точка зрения. А на практике ещё в строю даже Cobol и Lisp. И не только.

Поддержка Unicode есть не только в Rust, но и во всех актуальных языках

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

s2 := Copy(s1, 1, 6);
и в результате скопировались бы именно 6 юникодных символов, а не 6 байтов. В то время как эта Copy() умеет работать и с однобайтными кодировками.

Та же strncpy() копирует именно по одному байту всегда.

saahriktu ★★★★★ ()

со строками начинают работать именно с юникодом, а не с отдельными байтами.

И что, нормализация и классы эквивалентности работают? Сомневаюсь, но если да, то круто.

Freyr69 ★★★ ()
Ответ на: комментарий от liberty1

Просто Паскаль (как и многие другие языки программирования) хейтят его неосиляторы.

В Паскале очень строгая типизация. В том же Си, например, совершенно спокойно можно присваивать переменным типа char числа, а в переменные типа int складывать символы без дополнительных преобразований. А в том же Паскале такая декларация переменной

d: Char = 10;
провалится с ошибкой
Error: Incompatible types: got "ShortInt" expected "Char"
Как и наоборот:
e: Integer = 't';
Error: Incompatible types: got "Char" expected "SmallInt"
Поэтому в Паскале тонны функций для конвертирования из одного типа в другой, которые просто обязательно применять.

Что, видимо, и напрягает людей.

saahriktu ★★★★★ ()
Ответ на: комментарий от RazrFalcon

Что мешает разбить функцию на несколько функций? Тогда в каждой новой функции будет своя собственная область видимости.

А определение переменных не в любом месте, а именно в самом начале, - это хороший стиль программирования, который упрощает отладку. Тогда не нужно лазить по всему коду в поисках того где и как именно была определена каждая из переменных.

saahriktu ★★★★★ ()
Последнее исправление: saahriktu (всего исправлений: 1)
Ответ на: комментарий от RazrFalcon

Я могу создать переменную в любом месте функции?

В большинстве диалектов — нет.
Delphi 10.3 Rio такой синтаксис получит. Не могу сказать, что это вот прямо сильно здорово, появится куча «спагетти» теперь и здесь.
http://blog.marcocantu.com/blog/2018-october-inline-variables-delphi.html

Я могу создать локальную область видимости?

Безымянную — не во всех. Именованную — в любом.

bormant ★★★★★ ()
Последнее исправление: bormant (всего исправлений: 1)
Ответ на: комментарий от RazrFalcon

Как будто нужно специально раздувать код. Код нужно оценивать не по количеству строк.

И, да, у меня тоже больше 10-ти строк. В последних двух читалках, например, так: в однобайтном варианте 386 строк кода, а в юникодном варианте 442 строки кода.

saahriktu ★★★★★ ()
Последнее исправление: saahriktu (всего исправлений: 1)
Ответ на: комментарий от RazrFalcon

Это юниксвей. Каждая софтина минималистична, поскольку должна выполнять только одну функцию. В итоге всё распределено между разными софтинами, многие из которых и так уже есть в системе, которые склеиваются через конвейер.

А комбайны, да, должны быть тяжёлыми.

saahriktu ★★★★★ ()
Последнее исправление: saahriktu (всего исправлений: 1)
Ответ на: комментарий от saahriktu

А определение переменных не в любом месте, а именно в самом начале, - это хороший стиль программирования, который упрощает отладку.

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

liberty1 ()
Ответ на: комментарий от liberty1

Не знаю что там с анализаторами, но у Паскаля (который разработан в т.ч и для обучения хорошему стилю программирования) именно такая идеология. Меня учили программированию в т.ч. и на примере Turbo Pascal'я. И что касается значения определения переменных в самом начале я лишь процитировал слова своих учителей.

saahriktu ★★★★★ ()
Ответ на: комментарий от RazrFalcon

Конечно удобно, раньше-то до C++11 приходилось писать:

for (std::vector<std::map<int, std::string>>::const_iterator it = container.begin(); it != container.end(); ++it)
а теперь разрешили
for (auto it = container.begin(); it != container.end(); ++it)
Много ли надо для счастья: заведи козу, выгони козу.

bormant ★★★★★ ()
Ответ на: комментарий от liberty1

Вы часто инкапсулируете отдельные осмысленные части задачи в безымянные блоки?
Объявление переменных по месту использования сложно назвать убойной фишкой, по крайней мере модули и локальные вложенные именованные блоки променять на нее не готов.

bormant ★★★★★ ()
Последнее исправление: bormant (всего исправлений: 1)
Ответ на: комментарий от bormant

Вы часто инкапсулируете отдельные осмысленные части задачи в безымянные блоки?

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

Объявление переменных по месту использования сложно назвать убойной фишкой

конечно, любители C89 приноровились разбивать код на кучу мелких функций

liberty1 ()