Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Ошибка преобразования RTF в PlainText через TRichEdit [D7]


sniknik ©   (2009-04-09 13:11:00) 

Делается преобразование текста в RTF из данных базы куда они попали нормальным редактированием (ошибок нет)  в компоненте TDBRichEdit каким образом - набором/копированием из буфера не знаю, я имею дело уже только с последствиями.

А последствия такие, после некоторых вариантов данных (фактически одного ;) компонент "виснет" не работают внесение в него нового текста, копирование из него и т.д., после сбоя он все время  отдает один и тот же текст...
Вот эмулятор, с выделенным сбойным текстом ->
На форму положить TRichEdit и TCheckBox в онклик чекбокса код - procedure TForm1.CheckBox1Click(Sender: TObject);
var
 Stream: TStringStream;
begin
 Stream:= TStringStream.Create(
   (*'{\rtf1\ansi\ansicpg1251\deff0\deflang1049{\fonttbl{\f0\fnil\fcharset204 MS Sans Serif;}{\f1\fmodern\fcharset204{\*\fname Courier New;}Courier New CYR;}}'+
   '\viewkind4\uc1\pard\f0\fs16'+
   '\par \''c2\''78\''78\''78\''78\''78:'+
   '\par \protect\f1\fs20\''ca\''ee\''ed\''f2\''e0\''ea\''f2 \''ef\''f0\''e5\''e4\''f1\''f2\''e0\''e2\''e8\''f2\''e5\''eb\''ff \''c2\''78\''78\''78\''78\''78 \'''+
     'e2 \''d7\''e5\''eb\''ff\''e1\''e8\''ed\''f1\''ea\''e5 0-000-000-00-00 \''cd\''78\''78\''78\''78\''78\''78\''78\''78 \''cf\''e0\''e2\''e5\''eb\protect0'+
   '\par \f0\fs16'+
   '\par }'*)

   '{\rtf1\ansi\ansicpg1251\deff0\deflang1049{\fonttbl{\f0\fnil\fcharset204 MS Sans Serif;}}'+
   '\viewkind4\uc1\pard\f0\fs16\''d1\''e5\''f0\''e3\''e5\''e9    000-00-00 \''e4\''ee\''e1. 000  \''ed\''e5 \''f0\''e0\''e1\''ee\''f2\''e0\''fe\''f2 \''f1\''f7\'''+
     'e5\''f2\''f7\''e8\''ea\''e8 \''ef\''ee\''f1\''e5\''f2\''e8\''f2\''e5\''eb\''e5\''e9.'+
   '\par  \''e3\''e0\''f0\''e0\''ed\''f2\''e8\''ff'+
   '\par }'
 );
 try
   RichEdit1.PlainText:= not CheckBox1.Checked;
   RichEdit1.Lines.LoadFromStream(Stream);
 finally
   Stream.Free;
 end;
end;

Сразу будет рабочий, посмотреть как должно быть, после комментируете одно раскомментируете другое и готов вариант как не работает... (если работает одинаково значит у вас не D7... ;))

Вопрос, что с этим делать? Есть вариант гарантированного преобразования и так чтобы не висло? (компонент без TRichEdit?)

Виснет не код дельфи, виснет объект винды,  при трассировке я доходил до посылки сообщения (Perform) с новым текстом, и он был действительно новый, но после, чтение получает старый...
Ну, а виндовый ВордПад, с ним нормально справляется, возможно это потому что у них 3й ричьэдит, а в дельфе первый, а текст как то получилось туда попал от третьего... х.з.

В принципе обошел тем, что вместо очистки текста в компоненте пересоздаю его... НО, заметил странную вещь, после десятка таких  глючных текстов подряд на тестах (по идее в реальности не бывает такого, этот то один раз за все пару лет встретился) у меня отключается VPN(!!!???) и начинаются другие странности в системе (например комп не выключился кнопкой из винды, что давно уже нонсенс).
В общем решил "это ЖЖЖЖЖ не спроста!", и надо чтото делать... вопрос что? (лучшим вариантом наверное был бы готовый парсер-преобразователь, но не знаю такого)

Что посоветуете?


sniknik   (2009-04-09 18:48:00) [1]

> Это простенький парсер
Уже вижу, с пробелами мудрит, лишних вставляет, даже на простых RTF-ах. Но, все не с 0 делать (тем более у меня почему то было впечатление, что там что-то невероятно сложное... тома документации по rtf-у голову запудрили... а ты можно сказать сломал этот психологический барьер ;)).


Rouse_   (2009-04-09 18:35:00) [2]

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


sniknik   (2009-04-09 18:31:00) [3]

> Тебе обычный Plain чтоль нужен?
Именно.
Х.м. а выглядит все проще чем ожидал... но работает. Спасибо.
Проверю на по всем значениям базы, и можно будет использовать.


Rouse_   (2009-04-09 18:24:00) [4]

Тебе обычный Plain чтоль нужен? Попробуй вот это (из каких-то старых запасников вытащил):

function RTF2PlainText(const Value: string): string;
var
 ACursor, I, Len, Tmp, SkipCount: Integer;
 Wait: Boolean;

 procedure CheckSize(const Offset: Integer);
 begin
   if I + Offset > Len then
     Abort;
 end;

begin
 Len := Length(Value);
 Result := StringOfChar(#0, Len);
 if Copy(Value, 1, 5) <> '{\rtf' then Exit;

 I := 2;
 ACursor := 1;
 SkipCount := 0;
 Wait := False;
 try
   while I < Len do
   begin
     case Value[I] of
       '{':
       begin
         Inc(SkipCount);
         Inc(I);
       end;
       '}':
       begin
         Dec(SkipCount);
         Inc(I);
       end;
       '\':
       begin
         if SkipCount > 0 then
         begin
           Inc(I);
           Continue;
         end;
         if Wait then
           Wait := False;
         CheckSize(1);
         if Value[I + 1] = '''' then
         begin
           CheckSize(3);
           Result[ACursor] :=
             Char(StrToInt('$' + Value[I + 2] + Value[I + 3]));
           Inc(ACursor);
           Inc(I, 4);
           Continue;
         end;
         CheckSize(4);
         if (Copy(Value, I, 4) = '\par') and (Value[I + 4] in ['\', ' ']) then
         begin
           Result[ACursor] := #13;
           Result[ACursor + 1] := #10;
           Inc(ACursor, 2);
           Inc(I, 4);
           Continue;
         end;
         if (Copy(Value, I, 4) = '\tab') and (Value[I + 4] in ['\', ' ']) then
         begin
           Result[ACursor] := #9;
           Inc(ACursor);
           Inc(I, 4);
           Continue;
         end;
         Wait := True;
         Inc(I);
       end;
       ' ':
       begin
         Result[ACursor] := Value[I];
         Inc(ACursor);
         Inc(I);
         Wait := False;
       end
     else
       if not Wait and (SkipCount = 0) then
       begin
         Result[ACursor] := Value[I];
         Inc(ACursor);
       end;
       Inc(I);
     end;
   end;
 except
   on E: EAbort do ;
     // nothing
   on E: Exception do
     raise;
 end;
 Result := PChar(Result);
end;


sniknik   (2009-04-09 18:21:00) [5]

> Что-то вроде:
Чтото вроде нифига не конвертит...

Пробую
SetRichText(
 RichEdit1.Handle,
 'тут все те же примеры RTF '
);
Memo1.Text:= GetRichText(RichEdit1.Handle);

Как был так и остался в кодах ртф-а, в плайн не преобразовывается... заменял флаги (TxtEx.flags) при внесении/чтении на SF_TEXT/SF_RTF по аналогии как при обычной работе, тоже самое (ну разве что если ставить SF_RTF при чтениии то вообще ничего не отдает).

Да и вообще, это же вроде как код присваивания юникода...? Чем он поможет?

> что riched32.dll (riched20.dll ?) не ахти
Пока искал, такого начитался... не "ахти" это ОЧЕНЬ, ОЧЕНЬ мягко и даже ласково... :)
(зато теперь понимаю почему борланд не спешил с переходом с 1-й на 3-ю версию)

KilkennyCat ©   (09.04.09 17:13) [3]
> и предлагал ее замену...
Замену придется "таскать" с собой, и без гарантий что что-то не поставят и не перетрут (офис по моему ставит свои).
Проще тогда поднапрячься и самому парсер написать, ведь для преобразования в плайн текст не обязательно полное соответствие формату (там у них по доке очень много), все непонятное будет откидываться.


KilkennyCat   (2009-04-09 17:13:00) [6]


> Что посоветуете?

Я лет 5 назад наткнулся на статью о глючности дллки. Не вспомню уже, в чем суть, но просто факт - товарищ признавал, что riched32.dll (riched20.dll ?) не ахти, и предлагал ее замену... с другой стороны, прошло много времени...


Romkin   (2009-04-09 15:49:00) [7]

Что-то вроде:

type
 SETTEXTEX = packed record
   flags: DWORD;              { flags (see the ST_XXX defines }
   codepage: UINT;            { code page for translation (CP_ACP for default,
                                1200 for Unicode }
 end;
 TSetTextEx = SETTEXTEX;
 GETTEXTEX = packed record
   cb: DWORD;                 { count of bytes in the string  }
   flags: DWORD;              { flags (see the GT_XXX defines }
   codepage: UINT;
   lpDefaultChar: LPCSTR;     { replacement for unmappable chars   }
   lpUsedDefChar: PBOOL;      { pointer to flag set when def char used  }
 end;
 TGetTextEx = GETTEXTEX;
 GETTEXTLENGTHEX = packed record
   flags: DWORD;              { flags (see the GTL_XXX defines }
   codepage:UINT;
 end;
 TGetTextLengthEx = GETTEXTLENGTHEX;

function GetTextLength(Handle: HWND): integer;
var
 txtLen: TGetTextLengthEx;
begin
 ZeroMemory(@TxtLen, SizeOf(TxtLen));
 txtLen.codepage := 1200;
 txtLen.flags := GTL_USECRLF + GTL_PRECISE + GTL_NUMCHARS;
 Result := SendMessage(Handle, EM_GETTEXTLENGTHEX, Longint(@TxtLen), 0);
end;

function GetRichText(Handle: HWND): WideString;
var
 TxtEx: TGetTextEx;
begin
 SetLength(Result, GetTextLength(Handle));
 if Result = '' then
   exit;
 ZeroMemory(@TxtEx, SizeOf(TxtEx));
 TxtEx.cb := (Length(Result) + 1) * SizeOf(WideChar);
 TxtEx.flags := GT_USECRLF;
 TxtEx.codepage := 1200;
 TxtEx.lpDefaultChar := nil;
 TxtEx.lpUsedDefChar := nil;
 SendMessage(Handle, EM_GETTEXTEX, Longint(@TxtEx),
   Longint(PWideChar(Result)));
end;

function GetRichSelection(Handle: HWND): WideString;
var
 TxtEx: TGetTextEx;
begin
 SetLength(Result, GetSelLength(Handle));
 if Result = '' then
   exit;
 ZeroMemory(@TxtEx, SizeOf(TxtEx));
 TxtEx.cb := (Length(Result) + 1) * SizeOf(WideChar);
 TxtEx.flags := GT_USECRLF + GT_SELECTION;
 TxtEx.codepage := 1200;
 TxtEx.lpDefaultChar := nil;
 TxtEx.lpUsedDefChar := nil;
 SendMessage(Handle, EM_GETTEXTEX, Longint(@TxtEx),
   Longint(PWideChar(Result)));
end;

procedure SetRichText(Handle: HWND; s: WideString);
var
 TxtEx: TSetTextEx;
begin
 if s = '' then
   s := #0;
 ZeroMemory(@TxtEx, SizeOf(TxtEx));
 TxtEx.flags := ST_DEFAULT;
 TxtEx.codepage := 1200;
 SendMessage(Handle, EM_SETTEXTEX, Longint(@TxtEx), Longint(PWideChar(s)));
end;


sniknik   (2009-04-09 13:28:00) [8]

p.s. если препарсить и самому убирать секции \protect, \protect0 то RTF становиться перевариваемым... но, как всегда, а это только от них зависит?


Наверх

Титульная страница Поиск, карта сайта Написать письмо