Работа с текстовыми строками в Lazarus

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Работа с текстовыми строками в Lazarus

Сообщение fflatx » 27.09.2008 01:57:22

Всем здравствуйте.

Учусь заочно в университете. Для решения учебной задачи создаю небольшое приложение для обработки строк (или текстовых файлов). В связи с проблемами лицензирования в университете отсутствует Дельфи и используется Лазарус. Соответственно задачу решаю в этой среде. ОС Linux Mandriva 2008.0, Лазарус 0.9.24, собран для gtk2+, чтобы работал русский интерфейс.
Трудность состоит в том, что в университете установлена Windows XP, следовательно имеется проблема с кодировками. Для моей задачи это критично, т.к. задача связана именно с обработкой текстовых данных.

Собственно проблема: в Дельфи и паскале переменные типа string представляют собой массив символов. И к отдельному символу можно обратиться по индексу. В Лазарусе при работе с кириллицей это срабатывает правильно для однобайтовых кодировок. Для UTF-8, используемой в Linux это не работает. Т.е. в Windows это работает, в Linux - нет.
Запуск Лазаруса в локали CP1251
$ LC_ALL=ru_RU.CP1251 ./startlazarus
а также использование функций UTF8toAnsi, UTF8decode не дают никакого эффекта. Символы в строке как были двухбайтовыми, так и остались.


Воспользовался гуглом, поиском по форуму, обнаружилось множество вариантов, вплоть до написания собственных модулей, но это показалось мне слишком громоздким. Я понимаю, что при желании можно написать любую функцию, но для чего тогда нужны все эти UTF8toAnsi, UTF8decode, если человек в результате пишет свою функцию?
Можно под вайном запустить виндовый Лазарус (и даже Дельфи), но все эти варианты я оставляю на крайний случай.
Я пытаюсь разобраться в проблеме, использовать кроссплатформенность Лазаруса и возможности тех функций, которые есть.

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

P.S. Прошу модераторов сильно не бить меня за создание этой темы.
fflatx
незнакомец
 
Сообщения: 5
Зарегистрирован: 27.09.2008 01:14:24

Re: Работа с текстовыми строками в Lazarus

Сообщение Sergei I. Gorelkin » 27.09.2008 10:07:32

Если уж переопределять локаль, то LC_ALL=ru_RU.CP1251 нужно указывать при запуске собственной программы, а не Лазаруса.
UTF8ToAnsi, как следует из названия, преобразует из utf-8 в текущую локаль системы, т.е. по умолчанию в линуксе получится опять utf-8. Кроме того, для ее работы к программе нужно подключать модуль cwstring.
UTF8Decode преобразует utf-8 в WideString (строку с двухбайтовыми символами, к которым можно обращаться по индексу - по крайней мере до тех пор, пока речь не зайдет об экзотике типа древнеегипетских иероглифов). Если результат присвоить переменной типа string, то компилятор вставит автоматическое преобразование и общий результат будет в точности таким же, как у UTF8ToAnsi.
Наконец, недавно в FPC добавили модуль iconvenc, позволяющий перекодировать с явным указанием исходной и целевой кодировок. Но он пока что не кроссплатформенный (только для *nix, хотя в природе есть и iconv.dll для Windows)
Все сказанное, собственно, относится только FPC и его библиотекам, но не к Лазарусу. Лазарус (точнее, LCL), надо полагать, имеет свой собственнй набор средств. Но пускай о нем расскажут люди более сведущие.
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1367
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Re: Работа с текстовыми строками в Lazarus

Сообщение Odyssey » 28.09.2008 22:53:22

Если кодировка исходных текстовых файлов не имеет значения, то можно хранить их в UTF-8, и обрабатывать в ней же. Работа с ней не намного сложнее, нужно только помнить про переменное число байт на символ. В модуле LCLProc есть функции для работы с UTF-8, например UTF8Pos, UTF8Copy, UTF8Delete, UTF8Insert, UTF8Length, а посимвольный доступ вместо s[i] можно получить с помощью UTF8CharStart(PChar(s), Length(s), i). Скорость будет несколько ниже чем при обработке ANSI-строк, но ее можно увеличить оптимизацией алгоритмов обработки.

Lazarus 0.9.26 в качестве внутренней кодировки LCL будет использовать UTF-8, поэтому опыт работы с ней может еще пригодится.
Odyssey
энтузиаст
 
Сообщения: 581
Зарегистрирован: 29.11.2007 17:32:24

Re: Работа с текстовыми строками в Lazarus

Сообщение Logo » 03.10.2008 04:51:29

Sergei I. Gorelkin писал(а):Наконец, недавно в FPC добавили модуль iconvenc, позволяющий перекодировать с явным указанием исходной и целевой кодировок.

Спасибо, очень помог.
Logo
постоялец
 
Сообщения: 464
Зарегистрирован: 20.08.2008 01:00:47

Re: Работа с текстовыми строками в Lazarus

Сообщение yad2000 » 25.12.2012 11:46:08

У меня аналогичная проблема (+/-).
Версия Lazarus 1.0.4.
Ось: W7x64

Пишу так:

Код: Выделить всё
procedure TForm1.addnewchars(var A:string;str:string); //Кусок 1
begin
   A:=A+UTF8Copy(str,Length(str),2); //Нужно к примеру 2-ой символ из str добавить A - буква "Б" - в этом примере/ и второй вопрос как правильно добавить все символы из str, обычный плюс почему то не добавляет
end;

procedure TForm1.init_mysymbols_var; //Кусок 2
begin
  mySymbols:= '';
  addnewchars(mySymbols,'АБГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзийклмнопрстуфхцчшщъыьэюя')); //Русский алфавит
end; 

procedure TForm1.Button3Click(Sender: TObject); //Кусок 3
begin
  Edit1.Text:=UTF8CharStart(PChar(mySymbols),1,codesymb); //codesymb меняется по таймеру от 0 до (UTF8Length(mySymbols)-1)
end;   


Итог: не работает, перерыл файл LCLProc - выход не нашел, прошу помощи здесь.

Добавление вначале этих строк - не помогло:
{$mode objfpc}
{$H+}
{$codepage UTF8}

Замена всех string на Unicodestring не помогло
Обращение к mySymbols обычными средствами и средствами UTF8xxxxx разных функций не помогло во множестве сочетаний

Использую шрифт в проекте и во всех компонентах @Arial Unicode MS

Ну и наконец вопросы:
1. Как все таки перебрать строку содержащую русские буквы посимвольно (?), в Delphi таких проблем не было
2. Как перебирать строку посимвольно содержащую не только русские буквы но и всякую экзотику Unicode. Допустим есть строка Unicodestring из 30 экзотических символов, и как получить доступ к любому из них?


В файле LazUTF8 есть функция:
Код: Выделить всё
function UTF8Length(p: PChar; ByteCount: PtrInt): PtrInt;
var
  CharLen: LongInt;
begin
  Result:=0;
  while (ByteCount>0) do begin
    inc(Result);
    CharLen:=UTF8CharacterLength(p);
    inc(p,CharLen);
    dec(ByteCount,CharLen);
  end;
end; 

которая вызывается функцией:
Код: Выделить всё
function UTF8Length(const s: string): PtrInt;
begin
  Result:=UTF8Length(PChar(s),length(s));
end;   

Это все наводит на мысль что к каждому символу нужно обращаться по байтам, но если есть строка содержащая символы разной длины в байтах, как определить это кол-во байт для нужного номера символа в массиве, изначально не зная что это за символ??? Вообще такое сделать реально???
yad2000
незнакомец
 
Сообщения: 2
Зарегистрирован: 25.12.2012 11:34:58

Re: Работа с текстовыми строками в Lazarus

Сообщение SSerge » 25.12.2012 14:15:56

yad2000 писал(а):{$codepage UTF8}


А вот нельзя в лазарусе это делать, как и применять соответствующий ключ компиляции. А если все же сделать, то внимательно трассировать что получается. И компилятор должен быть 2.7.х, в 2.6.0 нет нормально работающих UnicodeStrings.
Если очень хочется, см. здесь: http://sirserge.altai.info/articles/?id=45
yad2000 писал(а):1. Как все таки перебрать строку содержащую русские буквы посимвольно (?),


Код: Выделить всё
Var symbol:string;

begin
for i:=1 to Utf8Length(s) do begin
   symbol:=UTF8Copy(s,i,1);
   if (symbol='Я') then ....;
end;


yad2000 писал(а): Как перебирать строку посимвольно содержащую не только русские буквы но и всякую экзотику Unicode. Допустим есть строка Unicodestring из 30 экзотических символов, и как получить доступ к любому из них?


Еще раз, UnicodeString мягко говоря несовместим с библиотеками LCL.
Лучше работать со строками UTF8 (тип string! ни в коем случае не UTF8String!). Посимвольный доступ как в предыдущем примере.
SSerge
энтузиаст
 
Сообщения: 784
Зарегистрирован: 12.01.2012 05:34:14
Откуда: Барнаул

Re: Работа с текстовыми строками в Lazarus

Сообщение yad2000 » 25.12.2012 15:42:46

SSerge - огромное спасибо за пол пинка ))) все заработало, 2 дня не мог разобраться :mrgreen:

теперь мой код принял вид:
Код: Выделить всё
//////////////////////////////////
function getUTFSymbol(str:string;i:integer):string; //Функция достает нужный мне символ по номеру
var rez:string;
begin
rez:= UTF8Copy(str,i,1);
Result:=rez;
end;
//////////////////////////////////
procedure TForm1.addnewchars(var A:string;str:string); //Функция добавляет str к A с проверкой уже имеющихся в A символов
var i:integer;
begin
  for i:=1 to Utf8Length(str) do
    begin
     if UTF8Pos(UTF8Copy(str,i,1),A)=0 then
     A:=A+UTF8Copy(str,i,1);
    end;
end; 
//////////////////////////////////
procedure TForm1.init_mysymbols_var; // процедура инициирует на старте программы строку mySymbols:string
begin
  //SetLength(mySymbols,1);
  mySymbols:= #39;     //Апостроф
  addnewchars(mySymbols,'!"#$%&()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~');  //Основная латиница
  addnewchars(mySymbols,'±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ'); //Дополнительная латиница-1
  addnewchars(mySymbols,'ĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſ'); //Расширенная латиница A
addnewchars(mySymbols,'ƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴǵǶǷǸǹǺǻǼǽǾǿȀȁȂȃȄȅȆȇȈȉȊȋȌȍȎȏȐȑȒȓȔȕȖȗȘșȚțȜȝȞȟȠȡȢȣȤȥȦȧȨȩȪȫȬȭȮȯȰȱȲȳȴȵȶȷȸȹȺȻȼȽȾȿɀɁɂɃɄɅɆɇɈɉɊɋɌɍɎɏ'); //Расширенная латиница B
  addnewchars(mySymbols,'ɐɑɒɓɔɕɖɗɘəɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯ');  //Фонетические знаки         
end; 


Пока все работает, если что - еще напишу ))
yad2000
незнакомец
 
Сообщения: 2
Зарегистрирован: 25.12.2012 11:34:58


Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 5

Рейтинг@Mail.ru