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

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

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

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

Сообщение virus_hm » 09.11.2009 13:04:49

Пишу функцию для приблизительного сравнения строк, ее нужно пихнуть в 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 13:28:58, всего редактировалось 1 раз.
virus_hm
новенький
 
Сообщения: 22
Зарегистрирован: 19.09.2009 23:52:40

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

Сообщение Mr.Smart » 09.11.2009 13:16:04

Для начала оформите свой вопрос. Воспользуйтесь тегом [code], а то читать не хочется!
Mr.Smart
долгожитель
 
Сообщения: 1796
Зарегистрирован: 29.03.2008 01:01:11
Откуда: из леса!

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

Сообщение betatester » 09.11.2009 13:38:46

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

В случае проблем - пишите. Я вам подскажу.
betatester
постоялец
 
Сообщения: 276
Зарегистрирован: 27.04.2007 22:21:45

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

Сообщение скалогрыз » 09.11.2009 19:46:30

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

жесть какая! )) можно ли узнать каноны твоей религии ненависти к стрингам?!
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

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

Сообщение Vadim » 10.11.2009 04:22:11

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

PChar - универсальный сишный вариант. ;)
Vadim
долгожитель
 
Сообщения: 4112
Зарегистрирован: 05.10.2006 08:52:59
Откуда: Красноярск

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

Сообщение betatester » 10.11.2009 12:48:29

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

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

А если все написать на функциях libc и glib, то и размер модуля будет маленьким, и все будет работать. Аналогично тому, как оно работает во всех прочих местах и программах Linux.
betatester
постоялец
 
Сообщения: 276
Зарегистрирован: 27.04.2007 22:21:45

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

Сообщение virus_hm » 10.11.2009 13:35:30

интересный вопрос, почему firebird руский текст передает в формате WideChar, по 2 байта на символ, а латиницу передает в PChar.
virus_hm
новенький
 
Сообщения: 22
Зарегистрирован: 19.09.2009 23:52:40

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

Сообщение скалогрыз » 10.11.2009 13:42:07

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 и более байтами.
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

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

Сообщение Vadim » 10.11.2009 14:34:00

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

Функция Length() измеряет длину строки или количество символов. И не более того... :)
Vadim
долгожитель
 
Сообщения: 4112
Зарегистрирован: 05.10.2006 08:52:59
Откуда: Красноярск

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

Сообщение Sergei I. Gorelkin » 10.11.2009 15:14:10

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


Это так, когда аргумент имеет тип string (или widestring). Но что будет, если он имеет типа PChar? Возможны два варианта: либо компилятор догадывается и вставляет вызов, аналогичный StrLen(), либо он преобразует аргумент в тип string, что означает ненавязчивое добавление выделения и освобождения памяти и блока try-except.
Вот кто может, не заглядывая в ассемблерный листинг, сказать, какой из двух вариантов имеет место быть?
Лично я вообще не понимаю, почему оно компилируется, зачем нужно было пихать подобные костыли "совместимости" в компилятор.
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1405
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

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

Сообщение скалогрыз » 10.11.2009 16:22:24

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


...в trunk есть функция: fpc_pchar_length... теперь перемешать и перепутать string и pchar гораздо проще :)
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

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

Сообщение virus_hm » 11.11.2009 15:41:05

извеняюсь за свою безграмотность, с PChar рабою первый раз.
Вопрос следующий почему если тип входных переменных PChar размер строки strlen возращает в два раза больше, а если тип установить PWideChar, то wcslen возращает размер в два раза меньше ??
Переменные передаются из базы firebird, вся база на UTF8. Как правиль определить длину строки в таком случае.
virus_hm
новенький
 
Сообщения: 22
Зарегистрирован: 19.09.2009 23:52:40

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

Сообщение скалогрыз » 11.11.2009 16:08:02

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

в 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 секунд:
если кому интересно, то тестовый проект
У вас нет необходимых прав для просмотра вложений в этом сообщении.
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

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

Сообщение Mr.Smart » 11.11.2009 16:35:04

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

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

Сообщение скалогрыз » 11.11.2009 16:52:07

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

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

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

След.

Вернуться в Lazarus

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

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

Рейтинг@Mail.ru