Преобразовать функцию в Delphi 2009/2010 (Unicode)
Я постепенно преобразовываю свой существующий код в 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 ответов
Если это были ваши РЕАЛЬНЫЕ функции, и вы просто пытаетесь заставить их работать, то:
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;
(на данный момент мы не используем D10, так что будьте осторожны!)
Проблема в Delphi заключается в строковых литералах, которые содержат символы вне базового диапазона ascii. Когда они передаются в строковые процедуры, не-ascii-символы заменяются знаками вопроса.
Чтобы избежать этого, приведите текстовые литералы к WideStrings перед передачей их в качестве параметра функции.
Я не знаю, относится ли это к подпрограмме StringReplace, но процедура поиска Delphi Pos/Posex не обрабатывает Unicode правильно. Нам пришлось заменить эти процедуры на наш собственный вариант. Для этой улучшенной подпрограммы важно убедиться, что параметры имеют тип WideString, а не тип обычной строки.
Мы сделали это в D7 при работе с Unicode, и все работает хорошо.
Хотя 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
переменные. На самом деле, они также работают найти на WideString
переменные, даже в старых версиях Delphi.
Основная проблема в вашем коде заключалась в том, что вы сохранили символ Unicode в строковом типе, отличном от Unicode.
Строка [1] не имеет версии Unicode
вместо этого попробуйте Чар.
Судя по описанию вашей проблемы, вы, кажется, обрабатываете строки в кодировке UTF8. Это почти всегда плохая идея. Сначала расшифруйте их в более разумное представление, а затем оперируйте ими. Когда вы закончите, вы можете снова закодировать все как UTF-8.
Я думаю, что тип данных для строк широких символов - "WString" в Delphi; не могу посмотреть прямо сейчас.