Rambler's Top100
"Knowledge itself is power"
F.Bacon
Поиск | Карта сайта | Помощь | О проекте | ТТХ  
 Круглый стол
  
Правила КС
>> Настройки

Фильтр вопросов
>> Новые вопросы
отслеживать по
>> Новые ответы

Избранное

Страница вопросов
Поиск по КС


Специальные проекты:
>> К л ю к в а
>> Г о л о в о л о м к и

Вопрос №

Задать вопрос
Off-topic вопросы

Помощь

 
 К н и г и
 
Книжная полка
 
 
Библиотека
 
  
  
 


Поиск
 
Поиск по КС
Поиск в статьях
Яndex© + Google©
Поиск книг

 
  
Тематический каталог
Все манускрипты

 
  
Карта VCL
ОШИБКИ
Сообщения системы

 
Форумы
 
Круглый стол
Новые вопросы

 
  
Базарная площадь
Городская площадь

 
   
С Л С

 
Летопись
 
Королевские Хроники
Рыцарский Зал
Глас народа!

 
  
ТТХ
Конкурсы
Королевская клюква

 
Разделы
 
Hello, World!
Лицей

Квинтана

 
  
Сокровищница
Подземелье Магов
Подводные камни
Свитки

 
  
Школа ОБЕРОНА

 
  
Арсенальная башня
Фолианты
Полигон

 
  
Книга Песка
Дальние земли

 
  
АРХИВЫ

 
 

Сейчас на сайте присутствуют:
 
 
 08:36 Geo
 
 
Во Флориде и в Королевстве сейчас  08:39[Войти] | [Зарегистрироваться]
Ответ на вопрос № 38009

23-11-2005 08:55
Можно ли в строке AnsiString хранить произвольные двоичные данные, которые в общем случае могут в середине содержать символы #0?

Собственно, сохранить-то их там не проблема, а будут  ли правильно работать строковые функции? Вдруг где-то внутри функции она приведет мою строку к промежуточному PChar и обломается на первом же #0?

Где-то тут уже упоминались смутные сведения, что StringReplace у кого-то не работает с #0.

Речь идет о принципах построения некоей коммуникационной библиотечки для общения с железякой в ее собственном бинарном формате. Как правильно работать с данными в этом случае?

[+] Добавить в избранные вопросы

Отслеживать ответы на этот вопрос по RSS

Ответы:


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

28-09-2006 05:29
Теперь уже не вспомню. Написал свою. Однако, и AnsiPos то же не всегда работает.

28-11-2005 07:59 | Сообщение от автора вопроса
Pos тоже не работает (глюки с национальными символами)

У меня так работает:

  i := Pos(#0'Фыва'#0'Пролд', #0#0'Йцукен'#0'Фыва'#0'НеПролд'#0'Фыва'#0'Пролд');
  //                          1 2 345678 9  0123 14 5678901 22
  ShowMessage(IntToStr(i)); // возврашает 22



А как не работает?

28-11-2005 01:53
Pos тоже не работает (глюки с национальными символами)

24-11-2005 06:59 | Сообщение от автора вопроса
В общем, пока что я пришел к выводу, что для хранения данных можно пользоваться типом строк AnsiString, а для обработки и анализа - только операции ' + = <> < > ' и обычные Pos, Length, Copy. Не работают Ansi-функции. Не работает StringReplace. Не работает RegExpr. В общем, поупражняюсь на уровне  школьного Turbo-Pascal. IMHO, дороговатую цену заплатил Borland за совместимость с null-terminated string.

24-11-2005 06:53
>>>Но это светит переписыванием всех вкусностей за которые мы любим строки, включая - о ужас - мои любимые регулярные выражения. Может, уже кто-то занимался этим?
Я думаю, это единственно правильный путь. Никаких опасностей преобразования строк и, в качестве бонуса для всех нас, регулярные выражения для произвольной последовательности вайт от  Fisher-а ;)

24-11-2005 05:20 | Комментарий к предыдущим ответам
Вообще-то при перекодировании из String в WideString (или в другую сторону) двоичные данные имеют тенденцию теряться (или, наоборот, появляются лишние данные). Например, символы #0.

24-11-2005 04:53
добавлю немного к ответу Антона Григорьева: Все равно проблема в тех же самых Ansi*строковых-функциях. Ведь они же предназначены для работы не только с AnsiString, как можно было бы подумать, но и с WideString это не правильно. когда ты передаешь widestring в функцию требующую в качестве параметра string, то неявно вызывается функция конвертации string->widestring и функция работает с string! а вообще бы хорошо бы что бы компилятор выдавал хотябы warning, а лучше бы error- несовпадение типов.

24-11-2005 04:25
Multibyte и Unicode - это разные вещи. В Unicode каждый символ занимает ровно два байта, и к ANSI это не имеет никакого отношения. Multibyte - это часть стандарта ANSI: для некоторых кодовых страниц, в которых слишком много символов, предусмотрены специальные последовательности, состоящие из двух байт, но кодирующие один символ. Получается, что разные символы кодируются разным количеством байт. Так что функции с префиксом Ansi работают с multibyte, но не работают с WideString, т.к. WideString - это Unicode, а не Multibyte.

WideString хорош тем, что это, по сути, обёртка над системным типом BSTR. В этом типе, как и в string, длина определяется не нулём, а хранится по отрицательному смещению (а вот счётчика ссылок у BSTR и, соответственно, у WideString, нет). Вот только не все системные Unicode'ные функции это осознают - некоторые работают только с PWIDECHAR, т.е. игнорируют длину по отрицательному смещению и считают строку до первого нуля. Поэтому использование WideString - это тоже не очень хорошо, тут тоже есть шанс нарваться. Хотя, я посмотрел навскидку коды - кажется, эти места успешно обойдены.

24-11-2005 04:03 | Комментарий к предыдущим ответам
в предыдущем ответе к type Str32 = String; надо еще добавить type Char = System.Char;//WideChar, если надо будет переключиться на widestring.

24-11-2005 03:58 | Сообщение от автора вопроса
Ещё лучше сразу переходить на WideString

А чем же это лучше? Все равно проблема в тех же самых Ansi*строковых-функциях. Ведь они же предназначены для работы не только с AnsiString, как можно было бы подумать, но и с WideString:

Delphi Language Reference /
About extended character sets:

Names of multibyte functions usually start with Ansi-. For example, the multibyte version of StrPos is AnsiStrPos.

24-11-2005 03:49
Могу предложить написанные давно функции. Кажется в рабочем состоянии (мне не критична скорость в разборе строки). Некоторые, например pos, можо оптимизировать. Опять же кажется, они не должны реагировать на #0. Если хочешь разбирайся.

type Str32 = String; //WideString;
//т.к. мне нужны были функции, раборающие с widestring.

procedure Insert(const Source: Str32; var Str: Str32; Index: Longint);
var
  StrLength, SourceLength: Longint;
begin
  StrLength := Length(Str);
  SourceLength := Length(Source);
  SetLength(Str, StrLength + SourceLength);
  Move(Str[Index], Str[Index + SourceLength], (StrLength - Index + 1) * SizeOf(Char));
  Move(Source[1], Str[Index], SourceLength * SizeOf(Char));
end;

procedure Delete(var Str: Str32; Index, Count: Longint);
var
  StrLength: Longint;
begin
  {S := Copy(S, 1, Index) + Source + Copy(S, Index + 1, Length(S) - Index)}

  StrLength := Length(Str);
  Move(Str[Index + Count], Str[Index], (StrLength - Count - Index + 1) * SizeOf(Char));
  SetLength(Str, StrLength - Count);
end;

function ComparePString(Str1: Pointer; Str1Length: Longint; Str2: Pointer;
  Str2Length: Longint; CaseSensitive: Boolean = False): Longint;
const
  _FlagCase: array[Boolean] of Longint = (NORM_IGNORECASE, 0);
  CompareResult: array[0..2] of Longint = (-1, 0, 1);
begin
  Result :=
    CompareResult[CompareString(LOCALE_USER_DEFAULT,
      _FlagCase[CaseSensitive], Str1, Str1Length, Str2, Str2Length) - 1]
end;

function CompareString(const Str1, Str2: Str32;
  CaseSensitive: Boolean = False): Longint;
begin
  Result := ComparePString(Pointer(Str1), Length(Str1), Pointer(Str2), Length(Str2), CaseSensitive);
end;

function Pos(const SubStr, Str: Str32; FromPos: Integer = 0; CaseSensitive: Boolean = True): Longint;
var
  Bool: Boolean;
  SubStrLength, StrLength, CurPos: Longint;
  TmpStr: Pointer;
begin
  Bool := False;

  if FromPos < 0 then FromPos := 0;

  CurPos := FromPos;

  if (Str = '') or (SubStr = '') then
  else begin
    SubStrLength := Length(SubStr);
    StrLength := Length(Str);

    if (SubStrLength > StrLength) then
    else begin
      TmpStr := Pointer(Integer(Pointer(Str)) + FromPos);

      while (not Bool) and (CurPos <= StrLength - SubStrLength) do
      begin
        Bool := (ComparePString(Pointer(SubStr), SubStrLength, TmpStr, SubStrLength, CaseSensitive) = 0);
        TmpStr := Pointer(Integer(TmpStr) + 1);
        Inc(CurPos);
      end;
    end
  end;

  if Bool then Result := CurPos else Result := 0;
end;

function StringReplace(const Str, OldPattern, NewPattern: Str32;
  Flags: TReplaceFlags): Str32;
var
  Offset, LengthOldPattern: Integer;
  NewStr: Str32;
begin
  NewStr := Str;
  LengthOldPattern := Length(OldPattern);
  Result := '';

  while NewStr <> '' do
  begin
    Offset := Pos(OldPattern, NewStr, 0, not (rfIgnoreCase in Flags));
    if Offset = 0 then
    begin
      Result := Result + NewStr;
      Break;
    end;
    Result := Result + Copy(NewStr, 1, Offset - 1) + NewPattern;
    Delete(NewStr, 1, Offset + LengthOldPattern - 1);
    if not (rfReplaceAll in Flags) then
    begin
      Result := Result + NewStr;
      Break;
    end;
  end;
end;


24-11-2005 03:16
переписать действительно нужно многое. Вылавливать по ходу возникновения проблем.
Ещё лучше сразу переходить на WideString

24-11-2005 02:33
to Григорий Цуканов: А почему только AnsiPos? А что еще нужно переписать? А что можно не переписывать? Где бы это узнать?

Можно я отвечу?

AnsiPos - потому что, если посмотреть её исходники, видно, что там аргумент приводится к PChar. Надо смотреть исходники каждой функции (модули SysUtils и StrUtils) и разбираться, где идёт преобразование к PChar, а где без этого обходятся.

24-11-2005 01:59 | Сообщение от автора вопроса
to Orinoko: в пилотном проекте у меня тоже уже все вроде бы заработало на string. Но, во-первых, такого рода проьлемы могут начать проявляться в будущем при каком-то сочетании данных - например приедет от железки несколько #0 подряд в какой-нибудь контрольной сумме блока. Во-вторых, сейчас речь идет уже о "расширении и углублении" библиотеки, наращивании на нее дополнительной функциональности, в частности прикладные обработчики кусков летящих данных, которые будут парсить их и извлекать нужную информацию. И страшно оставлять в ядре системы не до конца проясненный вопрос.

to Алексей Румянцев: если бы они выдавали 'фи', все было бы хорошо. Но ведь они просто будут тихонько работать неправильно при некотором наборе входных данных. И это печально.

to Григорий Цуканов: А почему только AnsiPos? А что еще нужно переписать? А что можно не переписывать? Где бы это узнать?

to panda: я сам чувствую что лучше. Но это светит переписыванием всех вкусностей за которые мы любим строки, включая - о ужас - мои любимые регулярные выражения. Может, уже кто-то занимался этим?

24-11-2005 00:08
Как правильно работать с данными в этом случае?
Лучше хранить бестиповый буфер (с указателем типа Pointer) или MemoryStream.

23-11-2005 23:03
AnsiPos точно нужно переписать

23-11-2005 09:35
Ответ простой - в string можешь что угодно хранить, а те функции что будут на это выдавать "фи" заменяй своими :o)

23-11-2005 09:15
Переменная типа String может хранить в себе все коды символов включая #0. У меня прекрасно всё работает в задаче, аналогично твоей (работаю с нестандартными железяками через COM-порт).

Добавьте свое cообщение

Вашe имя:  [Войти]
Ваш адрес (e-mail):На Королевстве все адреса защищаются от спам-роботов
контрольный вопрос:
Раз дощечка, два дощечка будет лесенка. Раз словечко, два словечко, будет ЧТО?
в качестве ответа на вопрос или загадку следует давать только одно слово в именительном падеже и именно в такой форме, как оно используется в оригинале.
Надоело отвечать на странные вопросы? Зарегистрируйтесь на сайте.
Тип сообщения:
Текст:
Жирный шрифт  Наклонный шрифт  Подчеркнутый шрифт  Выравнивание по центру  Список  Заголовок  Разделительная линия  Код  Маленький шрифт  Крупный шрифт  Цитирование блока текста  Строчное цитирование
  • вопрос Круглого стола № XXX

  • вопрос № YYY в тесте № XXX Рыцарской Квинтаны

  • сообщение № YYY в теме № XXX Базарной площади
  • обсуждение темы № YYY Базарной площади
  •  
     Правила оформления сообщений на Королевстве

    Страница избранных вопросов Круглого стола.
      
    Время на сайте: GMT минус 5 часов

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

    Web hosting for this web site provided by DotNetPark (ASP.NET, SharePoint, MS SQL hosting)  
    Software for IIS, Hyper-V, MS SQL. Tools for Windows server administrators. Server migration utilities  

     
    © При использовании любых материалов «Королевства Delphi» необходимо указывать источник информации. Перепечатка авторских статей возможна только при согласии всех авторов и администрации сайта.
    Все используемые на сайте торговые марки являются собственностью их производителей.

    Яндекс цитирования