Как использовать новые типы строк в Delphi Xe2? - PullRequest
4 голосов
/ 01 января 2012

Обратите внимание, sarnold сильно отредактировал вопрос; оригинал вопрос, в целом, сохраняется в вопросе в качестве комментария. Если бы я сделал что-то непонятное, возможно оригинальный пост будет полезен. (Я выхожу это как комментарий, поэтому будущие редакторы не всегда должны ссылаться на история изменений вопроса.)

Я работаю с Delphi Xe2 и мне нужна помощь, чтобы понять, как использовать ANSI строки, строки Юникода и строки широких символов, правильно, особенно при написании DLL, предназначенной для использования с другими языками (например, как VB, C ++ или C #).

Мне нужно написать DLL, используя Delphi Xe2 для выполнения простых строковых операций. на строки Юникода. Эта DLL должна работать с одним SimpleShareMem или ShareMem или без диспетчеров памяти. Эта DLL должна быть вызываемой из-за рубежа такие языки, как VB, C ++ и C #.

По умолчанию строки теперь должны быть строками Unicode. Должны ли мы использовать Embarcadero для работы с этими строками?

Строки являются либо: (a) однобайтовыми символами, которые не поддерживают Unicode или (b) широкие строки, где каждому символу требуется два байта. (Эти делают поддерживает Unicode, но они не являются строками UTF-8.)

Доступны два типа указателей: PAnsiChar и PWideChar (есть указатель PUnicodeChar недоступен). PChar это псевдоним для PWideChar - означает ли это, что нам всегда нужно выделять 2 * length объем памяти для этих строк? (И, аналогично, мы должны делить память на 2 чтобы получить длину этих строк?)

Для строковых констант нам нужно пометить тип строки в исходный код? E.g.:

Const MyCo = 'test';

или

Const MyCo = WideString('test');

Как насчет того, когда мы выполняем присваивания между строковыми переменными?

s := st;

Если это будет переписано:

s := WideString(st);

Должны ли мы включить метку порядка байтов Unicode в наши строки? Как должен мы включаем спецификацию в наши строки?

Как мы должны работать со строками ANSI в разных кодовых страницах Windows? Если мы получаем строку ANSI с кодовой страницей 1200, если мы перекодируем строка или работа с ней как есть?

Как мы должны использовать класс TEncoding для преобразования между Unicode, UTF-8, Классы WideString и AnsiString?

Существуют ли какие-либо серьезные потери производительности при использовании широких строк или Unicode? строки?

Должны ли мы писать наши интерфейсы, чтобы требовать работы только с WideString варианты при использовании общего менеджера памяти?

Должны ли мы писать наши интерфейсы, чтобы требовать параметры длины для PChar, PAnsiChar и PWideChar типы параметров?

Как написать наши интерфейсы, чтобы определить, хранится ли файл в Unicode, UTF-8, ANSI или широкие символы? Как мы должны определить, какой формат использовать при записи файлов обратно?

Должны ли мы использовать только процедуры? Или функции тоже могут работать?

Спасибо, и с новым годом.

Ответы [ 3 ]

5 голосов
/ 01 января 2012

У меня сложилось впечатление, что Гу переходит с Delphi 7 на версию с поддержкой Unicode (D2009 +) и ищет совет о том, как работать с новыми строками.

Белая книга Кэри Дженсена Миграция Delphi Unicode для простых смертных , решает большинство, если не все вопросы, поднятые в вопросе.

Обычно я бы поместил это в комментарии, но список комментариев уже настолько длинный, что я чувствовал, что ссылку (которая может помочь большему количеству людей, чем просто Гу) легче найти в ответе.

1 голос
/ 02 января 2012
  • ShareMem и SimpleShareMem могут использоваться для совместного использования библиотек DLL с использованием строковых параметров только среди приложений Delphi, которые используют одинаковые модули.Они гарантируют, что и приложение, и DLL используют один и тот же диспетчер памяти.Вы не можете использовать их вне Delphi, потому что VB, C ++ и C # каждый будет использовать свой собственный менеджер памяти.Структура памяти типов строк Delphi совместима с другими языками (и наоборот), но строки должны быть выделены и освобождены с использованием одного и того же менеджера памяти.
  • Unicode-строки Delphi являются строками UTF-16, поскольку это «родная» Windowsтип строкиОн может поддерживать несколько 8-битных кодировок, включая UTF-8, с его типом AnsiString.
  • UTF-16 не всегда использует 2 байта на «символ».Некоторые «символы» могут использовать 4 байта, хотя они обычно появляются, только если вы выполняете некоторую «экзотическую» обработку текста (музыкальные символы, мертвые языки и т. Д.)
  • Преобразование строк в Unicode без потерь.В противном случае вы должны убедиться, что каждая AnsiString использует правильную кодовую страницу, чтобы избежать потери конверсии.Имейте в виду, что многие подпрограммы проходят преобразования Unicode, поэтому может быть лучше преобразовать любую не-Unicode строку в Unicode и, возможно, преобразовать обратно в качестве конечной операции (если не требуется обработка, специфичная для кодирования)
  • Поскольку строки в кодировке Юникод являются типом по умолчанию как в Delphi, так и в Windows, производительность должна быть выше, потому что преобразование туда и обратно не требуется.Пользовательский код, работающий со строками UTF-16, может быть медленнее, хотя из-за более сложной обработки (хотя UTF-8 может быть даже более сложным, как некоторые кодировки MBCS).
  • Спецификация обычно используется втекстовые файлы, а не для строк в памяти.Данные извне должны быть преобразованы в собственный формат в памяти при чтении / получении.В противном случае преобразование в собственный формат будет необходимо всякий раз, когда строка передается функции, которая ожидает этого.Выходная форма зависит от вашего приложения, вам нужен код, который может ее определить или спросить у пользователя.
0 голосов
/ 01 января 2012

КАК, вам лучше задать этот вопрос на форуме rsdn.ru, я чувствую, что они более либеральны для новичков, чем DelphiMasters.Это все там, просто прочитайте с вниманием и вниманием.

1) вам вообще НЕ следует создавать DLL.Вы должны сделать BPL.DLL предназначена для взаимодействия с простым интерфейсом C, таким как Win32 API.Это самые примитивные типы без каких-либо побочных эффектов.C называют «машинно-независимым» ассемблером за его примитивность, а интерфейс DLL является своего рода.

DLL может использоваться для совместимости с другими языками, потому что они используют другие побочные эффекты, несовместимые с Delphi.Затем DLL обеспечивает наиболее примитивное взаимодействие, при этом все побочные эффекты удаляются из интерфейса.Понижая уровень взаимодействия до большинства упрощенных типов, интерфейс DLL обеспечивает совместимость.

Но когда вам нужно взаимодействовать с Delphi и Delphi, вам лучше разрешить Delphi заботиться обо всех проблемах совместимости.это то, для чего BPL создан в Delphi 3. Для этого просто нет причин использовать DLL.

Конечно, вы можете застрелиться в ноге, если хотите.https://forums.embarcadero.com/thread.jspa?threadID=64114

2) Вы не должны использовать WideString в XE2, а вместо этого использовать UnicodeString.Руководство по строкам особенно подчеркивает это.Похоже, вы просто не читали руководство.

3) строковые константы в Unicode.(но символьные константы находятся в ... в ANSI или в Unicode случайным образом, что приводит к неожиданным ошибкам в поведении).И нет необходимости просить и доверять чьим-либо словам - просто откройте свой exe в любом средстве просмотра и найдите эти константы, вы найдете их в 2-байтовой кодировке UCS-2 (aka WideChar).

4) ЮникодСпецификация используется для определения порядка байтов ЦП, будь то Intel или Motorola.Когда вы разрабатываете для Windows, у вас может быть только порядок байтов Intel, поэтому нет необходимости в спецификации.

5) весь параграф, который вы написали о длинах и размерах памяти, очень неоднозначен.Что вы имеете в виду под длиной, в каких единицах измерения она измеряется, откуда вы берете ее?

Я предполагаю, что под длиной вы подразумевали количество символов, не включающее какие-либо служебные структуры / символы "под капотом".Это то, что возвращает встроенная функция System.Length (строка или массив).Однако, если это предположение неверно, то и приведенный ниже ответ тоже становится неправильным.

И вопрос о том, следует ли вам умножить на 2, является просто признаком плохого кода.Вы всегда должны умножаться на что-то, годы назад вы уже должны умножаться.Умножить на ... что?По SizeOf (используется переменная типа char) или SizeOf (используется тип char).Тогда t будет Delphi, который автоматически определит, сколько памяти необходимо.И при работе с C-строкой вы должны использовать не длину, а длину + 1 - не забывайте о терминаторе # 0.

6) Как мы должны работать со строками ANSI в разных кодовых страницах Windows?Если мы получим строку ANSI с кодовой страницей 1200, должны ли мы перекодировать строку или работать с ней как есть?

RTFM !!!Просто объявите тип AnsiString с кодовой страницей 1200. или используйте RawByteStrnig и SetCodePage.Читайте настоящий код ниже.

Опять RTFM - это ВСЕ описано во встроенной справке.Это займет всего 2 часа, чтобы прочитать это ВСЕ во встроенной справке Delphi XE2.

7) как нам использовать класс TEncoding для преобразования между классами Unicode, UTF-8, WideString и AnsiString? TEncoding сделан для TStringList или чего-то в этом роде.Почему ты должен?Существует тип UTF8String - просто используйте его.

var as: AnsiString;ucs2s: строка;utf8string: UTF8String;... as: = ucs2;utf8s: = как;....

8) Существуют ли какие-либо серьезные ограничения производительности при использовании широких строк или строк Unicode? Это зависит от того, какой "Unicode" вы имеете в виду, UCS-2 или UTF8.И какие операции вы хотите использовать.Просто сделайте лунный цикл и измерьте время.

9) Должны ли мы написать наши интерфейсы, чтобы требовать параметры длины для типов параметров PChar, PAnsiChar и PWideChar? Это ваш выбор, делайте, как хотите. Обычно PChar - это C-строка, заканчивающаяся # 0. И вот как работает функция StrLen. Если вы игнорируете это соглашение и используете его как нетипизы Pointer - тогда передайте длину отдельно.

ВСЕ эти вопросы уже даны в помощь !!! Просто прочитайте это.


function CDF_File_Buffer.GetStringNoBounds(const ofs, len: integer): string;
// Распознать кодировку, не проверять адреса
var cntDOS, cntWin, cntWeird, i : Cardinal;
    sBuf: RawByteString; cp: word;
    ptr, ptr_i: PAnsiChar;
const rusDOS: set of AnsiChar = [#$80..#$AF, #$E0..#$F1];
      rusWin: set of AnsiChar = [#$C0..#$FF];
begin
   ptr := Pointer(Header);  Inc(ptr, ofs);

   case textCharset of
     tcsGuess:
       begin
           ptr_i := ptr;  cntDOS :=0; cntWin :=0; cntWeird:=0;
           for i := 1 to len do begin
               if ptr_i^ in rusDOS then Inc(cntDOS);
               if ptr_i^ in rusWin then Inc(cntWin);
               if (ptr_i^ < #32) or ((ptr_i^ >= #127) and not(ptr_i^ in rusWin) and not(ptr_i^ in rusDOS))
                   then inc(cntWeird);

               Inc(ptr_i);
           end;
           if (cntWin > cntDOS) or (cntWeird > cntDOS) then cp := 1251 else cp := 866;
       end;
     tcsWin: cp := 1251;
     tcsDOS: cp := 866;
     else cp := 0; // быть не должно такого
   end;

   SetString(sBuf,ptr,len); 

   for i := 1 to Length(sBuf) do  if sBuf[i] = #0 then sBuf[i] := #7;
   // Не совсем корректно заменять нули, но
   // 1) неизвестно, что вообще в этом поле может быть
   // 2) файлы создаются в программе на C++, где нулей в строках не может быть
   // 3) семантику надо выводить на экран, а Windows написана на C++

   SetCodePage(sBuf, cp, false);

   Result := string(sBuf);
end;

function CDF_File_Buffer.GetString(const ofs, len: integer; const min, max: integer): string;
begin
  if (ofs <= 0) or (len <= 0) then
     Exit( '--- нет текста ---');

  if Cardinal(ofs + (len-1)) >= TotalSize then //меньше нуля уже не будет, убираем Warning
     Exit('--- За пределами файла ---');

  Result := '--- За пределами допустимой области: слишком близко к ';
  if ofs < min then Exit(Result + 'началу ---');
  if ofs + (len-1) > max then Exit(Result + 'концу ---');

  Result := GetStringNoBounds(ofs, len);
end;

function CDF_File_Buffer.GetString(const ofs, len: integer): string;
begin
  Result := GetString(ofs, len, 0, TotalSize-1);
end;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...