преобразовать функцию в Delphi 2009/2010 (Unicode) - PullRequest
1 голос
/ 07 октября 2009

Я постепенно преобразовываю свой существующий код в Delphi 2010 и читаю несколько статей на веб-сайте Embarcaedro, а также технический документ Marco Cantú.

Есть еще некоторые вещи, которые я не понял, поэтому вот две функции, иллюстрирующие мой вопрос:

function RemoveSpace(InStr: string): string;
var
  Ans     : string;
  I       : Word;
  L       : Word;
  TestChar: string[1];
begin
  Ans := '';
  L := Length(InStr);
  if L > 0 then
  begin
    for I := 1 to L do
    begin
      TestChar := Copy(InStr, I, 1);
      if TestChar <> ' ' then Ans := Ans + TestChar;
    end;
  end;
  RemoveSpace := Ans;
end;

function ReplaceStr(const S, Srch, Replace: string): string;
var
  I: Integer;
  Source: string;
begin
  Source := S;
  Result := '';
  repeat
    I := Pos(Srch, Source);
    if I > 0 then begin
      Result := Result + Copy(Source, 1, I - 1) + Replace;
      Source := Copy(Source, I + Length(Srch), MaxInt);
    end
    else Result := Result + Source;
  until I <= 0;
end;

Для функции RemoveSpace, если не передан символ Юникода (например, «aa bb»), все в порядке. Теперь, если я пропущу текст «ab cd», то функция не будет работать должным образом (я получаю ab ?? cd в качестве вывода).

Как я могу учесть возможные символы Юникода в строке? использование Length (InStr), очевидно, неверно, так же как и Copy (InStr, I, 1).

Как лучше всего преобразовать этот код, чтобы он учитывал символы Юникода?

Спасибо!

Ответы [ 5 ]

14 голосов
/ 07 октября 2009

Если это были ваши РЕАЛЬНЫЕ функции и вы просто пытаетесь заставить их работать, то:

function RemoveSpace(const InStr: string): string;
begin
  Result := StringReplace(InStr, ' ', '', [rfReplaceAll]); 
end;

function ReplaceStr(const S, Srch, Replace: string): string;
begin
  Result := StringReplace(S, Srch, Replace, [rfReplaceAll, rfIgnoreCase]); 
end;
1 голос
/ 07 октября 2009

Хотя string теперь является типом Unicode, когда вы указываете длину, вы все равно получаете не * Unicode ShortString тип. Переменная TestChar в вашей функции RemoveSpace является односимвольной строкой, отличной от Unicode. То, что вы должны были использовать все время, это настоящая Char переменная. Я ожидаю, что вы пришли из мира VB, где односимвольные строки были такими же, как одиночные символы. В Delphi строка не совпадает с символом, поэтому при вызове Copy вы получаете строку.

В Unicode Delphi эта односимвольная строка преобразуется в строку, отличную от Unicode, и, если в текущей кодовой странице нет представления для этого символа, вы получите знак вопроса. Исправьте это так:

function RemoveSpace(const InStr: string): string;
var
  I: Integer;
  TestChar: Char;
begin
  Result := '';
  for I := 1 to Length(InStr) do
  begin
    TestChar := InStr[I];
    if TestChar <> ' ' then
      Result := Result + TestChar;
  end;
end;

Я избавился от Ans. Начиная с Turbo Pascal 7, вы можете использовать неявно объявленную переменную Result вместо того, чтобы объявлять свою собственную, а затем назначать ее для имени функции. Result доступен для чтения и записи. Кроме того, вам не нужно беспокоиться о вводе нулевой длины. Когда верхняя граница цикла «for-to» меньше нижней границы, цикл просто не запускается, поэтому вам не нужно проверять заранее. Наконец, я использовал скобочные операторы в InStr для извлечения символа по указанному индексу вместо получения строки длиной в один символ.

Вы говорите, что вы используете Length и Copy, очевидно, неправильно, но вы ошибаетесь. Эти функции продолжают отлично работать в Unicode. Они знают, что Char теперь имеет ширину в два байта, поэтому, если вы вызовете их для UnicodeString переменных, вы получите правильные символы. Они также продолжают работать с AnsiString переменными. Фактически, они также работают с переменными find WideString, даже в старых версиях Delphi.

Основная проблема в вашем коде заключалась в том, что вы сохранили символ Unicode в строковом типе, отличном от Unicode.

1 голос
/ 07 октября 2009

(на данный момент мы не используем D10, так что будьте осторожны!)

Проблема в Delphi заключается в строковых литералах, которые содержат символы вне базового диапазона ascii. Когда они передаются в строковые процедуры, не-ascii-символы заменяются знаками вопроса.

Чтобы избежать этого, приведите текстовые литералы к WideStrings перед передачей их в качестве параметра в функцию.

Я не знаю, применимо ли это к подпрограмме StringReplace, но подпрограмма поиска Delphi Pos / Posex неправильно обрабатывает Unicode. Нам пришлось заменить эти процедуры на наш собственный вариант. Для этой улучшенной подпрограммы важно убедиться, что параметры имеют тип WideString, а не тип обычной строки.

Мы сделали это в D7 при обработке Unicode, и все работает хорошо.

0 голосов
/ 03 февраля 2010

Строка [1] не имеет версии Unicode

вместо этого попробуйте Char.

0 голосов
/ 07 октября 2009

Судя по описанию вашей проблемы, вы, похоже, обрабатываете строки в кодировке UTF8. Это почти всегда плохая идея. Сначала расшифруйте их в более разумное представление, а затем оперируйте ими. Когда вы закончите, вы можете снова закодировать все как UTF-8.

Я думаю, что тип данных для строк широких символов в Delphi - "WString"; не могу посмотреть прямо сейчас.

...