работа со строками

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

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

virus_hm
новенький
Сообщения: 22
Зарегистрирован: 19.09.2009 23:52:40

работа со строками

Сообщение virus_hm »

Пишу функцию для приблизительного сравнения строк, ее нужно пихнуть в so и использовать из firebird 2.1.3.
Вот уже 3 дня долбусь об стену с натписю UTF8 :cry: .
Брал готовые функции , работаю в тексте програмы из firebird результат неверный.
Решил сам написать по алгоритму, что бы разобратца как работает и в чем проблема, функция есть а результата нет.

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

function MyCompareStr(Search, Etalon: PChar): integer;
var
   j: integer;
   SubStr: PChar;
   Count: integer =0;
   SubStrLen: integer;
   SubStrCountS: integer;
   SubStrCountE: integer;
   CountLike: integer = 0;
   MaxSubStrLen: integer = 4;
begin
     Result:=0;
     if (Length(Search)=0) or (Length(Etalon)=0) then exit;
     if min(Length(Search),Length(Etalon))<MaxSubStrLen then
        MaxSubStrLen:=min(Length(Search),Length(Etalon));
     Search:=PChar(UpperCase(Search));
     Etalon:=PChar(UpperCase(Etalon));
     for SubStrLen:=1 to MaxSubStrLen do begin
         SubStrCountS:=Length(Search)-SubStrLen+1;
         for j:=1 to SubStrCountS do begin
             SubStr:=PChar(Copy(Search,j,SubStrLen));
             if pos(SubStr,Etalon)<>0 then
                inc(CountLike);
             inc(Count);
         end;
         SubStrCountE:=Length(Etalon)-SubStrLen+1;
         for j:=1 to SubStrCountE do begin
             SubStr:=PChar(Copy(Etalon,j,SubStrLen));
             if pos(SubStr,Search)<>0 then
                inc(CountLike);
             inc(Count);
         end;
     end;   
     Result:=trunc((CountLike/Count)*100);
end;     

Может не идеал но моих небольших расчетов подходит. В тексте програмы все работает, через firebird полная ерунда получается.
Подскажите как заставить ее работать.
Последний раз редактировалось virus_hm 09.11.2009 12:28:58, всего редактировалось 1 раз.
Mr.Smart
долгожитель
Сообщения: 1796
Зарегистрирован: 29.03.2008 00:01:11
Откуда: из леса!

Сообщение Mr.Smart »

Для начала оформите свой вопрос. Воспользуйтесь тегом [code], а то читать не хочется!
betatester
постоялец
Сообщения: 276
Зарегистрирован: 27.04.2007 22:21:45
Контактная информация:

Сообщение betatester »

1. Не пользуйтесь строками (тип String). Вообще.
2. Перейдите на голый PChar.
3. Если код пишется под Linux - посмотрите соотв. функции в библиотеках libc и glib. Там есть все необходимые функции для работы с UTF8.

В случае проблем - пишите. Я вам подскажу.
скалогрыз
долгожитель
Сообщения: 1804
Зарегистрирован: 03.09.2008 02:36:48

Сообщение скалогрыз »

betatester писал(а):1. Не пользуйтесь строками (тип String). Вообще.
2. Перейдите на голый PChar.
3. Если код пишется под Linux - посмотрите соотв. функции в библиотеках libc и glib. Там есть все необходимые функции для работы с UTF8.

жесть какая! )) можно ли узнать каноны твоей религии ненависти к стрингам?!
Vadim
долгожитель
Сообщения: 4112
Зарегистрирован: 05.10.2006 08:52:59
Откуда: Красноярск

Сообщение Vadim »

скалогрыз писал(а):можно ли узнать каноны твоей религии ненависти к стрингам?!

PChar - универсальный сишный вариант. ;)
betatester
постоялец
Сообщения: 276
Зарегистрирован: 27.04.2007 22:21:45
Контактная информация:

Сообщение betatester »

скалогрыз писал(а):жесть какая! )) можно ли узнать каноны твоей религии ненависти к стрингам?!
Ничего личного.

В приведенном примере речь идет о функции, вызываемой внешней программой. Параметры передаются в виде PChar. Обработка их в String - это минимум двойное преобразование. Это медленно и неэффективно. В данном конкретном случае. Более того, если "пихнуть код в *.so", то String потянет туда кучу лишнего кода - значительную часть RTL как минимум.
Я уже не говорю про то, что все системные вызовы Linux работают с PChar и про строки ничего не знают. Зато хорошо знают про UTF-8. :)

А если все написать на функциях libc и glib, то и размер модуля будет маленьким, и все будет работать. Аналогично тому, как оно работает во всех прочих местах и программах Linux.
virus_hm
новенький
Сообщения: 22
Зарегистрирован: 19.09.2009 23:52:40

Сообщение virus_hm »

интересный вопрос, почему firebird руский текст передает в формате WideChar, по 2 байта на символ, а латиницу передает в PChar.
скалогрыз
долгожитель
Сообщения: 1804
Зарегистрирован: 03.09.2008 02:36:48

Сообщение скалогрыз »

virus_hm писал(а):Решил сам написать по алгоритму, что бы разобратца как работает и в чем проблема, функция есть а результата нет.


какие должна возвращать и делать функция? честно говоря, функция походит на поиск подстроки в строке...

но даже не зная этого, есть следующие ошибки,
1)

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

     if (Length(Search)=0) or (Length(Etalon)=0) then exit;
     if min(Length(Search),Length(Etalon))<MaxSubStrLen then
        MaxSubStrLen:=min(Length(Search),Length(Etalon));

каждый вызвов length (возможно,по крайней мере первый раз точно) пересоздаёт строку! что очень неэффективно! правильно явно преобразовать к строке 1 раз.

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

var
  s, e : string;
begin
  s := Search;
  e := Etalon;
   if (Length(s)=0) or (Length(e)=0) then exit;
   if min(Length(s),Length(e))<MaxSubStrLen then
      MaxSubStrLen:=min(Length(s),Length(e));


2)

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

  Search:=PChar(UpperCase(Search));
  Etalon:=PChar(UpperCase(Etalon));

здесь же код преобразуется 3 раза (pchar->string->pchar)... причём с дальнейшей возможной ошибкой и утечками памяти...
Кроме того, функция UpperCase не понимает UTF8 (только ansi), а это значит, что исходные строки искажаются

(до неузнаваемости, там где, например была буква "м", закодированная "Pm", получилась буква "з", закодированная "PM". Допустим есть строка "мама", её utf8 код выглядит как: "PmPaPmPa", после функции UpperCase(), получаем PMPAPMPA, или "зюзю".
на самом деле utf8 коды другие... здесь привёл для примера понимания ситуации)

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

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

  s:=UTF8Encode(WideUpperCase(UTF8Decode(s)));
  e:=UTF8Encode(WideUpperCase(UTF8Decode(e)));


3)
почитай особенности кодировки utf8
все символы до 127 (включительно) это 1 байт байт, всё что после кодируются 2 и более байтами.
Vadim
долгожитель
Сообщения: 4112
Зарегистрирован: 05.10.2006 08:52:59
Откуда: Красноярск

Сообщение Vadim »

скалогрыз писал(а):каждый вызвов length (возможно,по крайней мере первый раз точно) пересоздаёт строку!

Функция Length() измеряет длину строки или количество символов. И не более того... :)
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
Сообщения: 1409
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Сообщение Sergei I. Gorelkin »

Vadim писал(а):Функция Length() измеряет длину строки или количество символов. И не более того...


Это так, когда аргумент имеет тип string (или widestring). Но что будет, если он имеет типа PChar? Возможны два варианта: либо компилятор догадывается и вставляет вызов, аналогичный StrLen(), либо он преобразует аргумент в тип string, что означает ненавязчивое добавление выделения и освобождения памяти и блока try-except.
Вот кто может, не заглядывая в ассемблерный листинг, сказать, какой из двух вариантов имеет место быть?
Лично я вообще не понимаю, почему оно компилируется, зачем нужно было пихать подобные костыли "совместимости" в компилятор.
скалогрыз
долгожитель
Сообщения: 1804
Зарегистрирован: 03.09.2008 02:36:48

Сообщение скалогрыз »

Sergei I. Gorelkin писал(а):Это так, когда аргумент имеет тип string (или widestring). Но что будет, если он имеет типа PChar? Возможны два варианта: либо компилятор догадывается и вставляет вызов, аналогичный StrLen(), либо он преобразует аргумент в тип string, что означает ненавязчивое добавление выделения и освобождения памяти и блока try-except.


...в trunk есть функция: fpc_pchar_length... теперь перемешать и перепутать string и pchar гораздо проще :)
virus_hm
новенький
Сообщения: 22
Зарегистрирован: 19.09.2009 23:52:40

Сообщение virus_hm »

извеняюсь за свою безграмотность, с PChar рабою первый раз.
Вопрос следующий почему если тип входных переменных PChar размер строки strlen возращает в два раза больше, а если тип установить PWideChar, то wcslen возращает размер в два раза меньше ??
Переменные передаются из базы firebird, вся база на UTF8. Как правиль определить длину строки в таком случае.
скалогрыз
долгожитель
Сообщения: 1804
Зарегистрирован: 03.09.2008 02:36:48

Сообщение скалогрыз »

есть красивое русское слово: "мама". (в этот раз специально использую точные символы)

в UTF8 кодировке, оно выглядит так: "мама"
hex: $D0 $BC $D0 $B0 $D0 $BC $D0 $B0

На каждый кирилический символ (как и на многие другие с кодом выше 127) выделяется 2 байта.
т.к. единица измерения функции length для типов (PChar, string, AnsiString) байты, то длинна строки получается: 8 (однобайтовых символов)

Для определения длины строки в текстовых символах (т.е. количество человеческих букв, а не кодирующих символов) есть дополнительные функции распознающие кодировку UTF8, например UTF8Length в модуле LCLProc. Для закодированной в utf8 "мама", UTF8Length вернёт 4.

------------

"мама" в кодировке UTF16 (которая применяется для PWideChar и WideString)
hex: $3C $04 $30 $04 $3C $04 $30 $04

На каждый символ (даже с кодом меньше 127) используется 2 байта.
единицей измерения функции length для типов (PWideChar, WideString) являются word-ы (2х байтовые величины), длина строки получается: 4 (двухбайтовых символа)

Добавлено спустя 19 минут 11 секунд:
если кому интересно, то тестовый проект
У вас нет необходимых прав для просмотра вложений в этом сообщении.
Mr.Smart
долгожитель
Сообщения: 1796
Зарегистрирован: 29.03.2008 00:01:11
Откуда: из леса!

Сообщение Mr.Smart »

скалогрыз
Зачем так разжевывать? Пусть люди научатся пользоваться документацией. Тем более про кодировку UTF-8 написано (в том числе и на русском) не так уж и мало!
скалогрыз
долгожитель
Сообщения: 1804
Зарегистрирован: 03.09.2008 02:36:48

Сообщение скалогрыз »

Mr.Smart писал(а):скалогрыз
Зачем так разжевывать? Пусть люди научатся пользоваться документацией. Тем более про кодировку UTF-8 написано (в том числе и на русском) не так уж и мало!

хз... преподавательские замашки?! :D

просто очень бесит, люди не разбираются в языке его возможностях, а так же типах данных, после этого пишут что паскаль это УГ или статьи вроде "Why pascal is not my favorite language".
За Державу обидно (c) :)
Ответить