Delphi XE AnsiStrings с экранированной комбинацией диакритических знаков
Каков наилучший способ преобразовать Delphi XE AnsiString, содержащую экранированную комбинацию диакритических меток, таких как "Fu\u0308rst", в дружественную WideString "Fürst"?
Я осознаю тот факт, что это не всегда возможно для всех комбинаций, но общие латинские блоки должны поддерживаться без создания собственных глупых таблиц преобразования. Я думаю, что решение может быть найдено где-то в новом модуле Персонажей, но я не понимаю его.
5 ответов
Я думаю, что вам нужно выполнить нормализацию Юникода. на твоей струне.
Я не знаю, есть ли конкретный вызов в Delphi XE RTL, чтобы сделать это, но вызов WinAPI NormalizeString должен помочь вам здесь, с режимом NormalizationKC:
NormalizationKC
Форма нормализации Юникода KC, состав совместимости. Преобразует каждый базовый плюс объединяющие символы в канонический предварительно составленный эквивалент, а все символы совместимости - в их эквиваленты. Например, лигатура becomes становится f + i; аналогично, A + ¨ + + + n становится Ä + f + i + n.
Вот полный код, который решил мою проблему:
function Unescape (const s: AnsiString): строка; вар я: целое число; j: целое число; с: целое число; начать // Сделать результат хотя бы достаточно большим. Это предотвращает слишком много перераспределения SetLength (Результат, Длина (с)); я:= 1; j:= 1; в то время как я <= длина (ы) действительно начинаются если s[i] = '\' тогда начинайте если я <Длина (ы), то начинайте // избежал обратной косой черты? если s [i + 1] = '\' тогда начинайте Результат [j]: = '\'; inc (i, 2); конец // конвертируем шестнадцатеричное число в WideChar иначе если (s [i + 1] = 'u') и (i + 1 + 4 <= длина (с)) и TryStrToInt ('$' + string (Copy (s, i + 2, 4)), c) затем начинаются inc (i, 6); Результат [j]: = WideChar (c); конец еще начало поднять Exception.CreateFmt ('Неверный код в позиции% d', [i]); конец; конец еще начало поднять Exception.Create ("Неожиданный конец строки"); конец; конец еще начало Результат [j]: = WideChar (s [i]); вкл (я); конец; вкл (J); конец; // Обрезать результат, если мы зарезервировали слишком много места SetLength (Результат, j - 1); конец; Const Нормализация C = 1; function NormalizeString (NormForm: Integer; lpSrcString: LPCWSTR; cwSrcLength: Integer; lpDstString: LPWSTR; cwDstLength: Integer): Integer; STDCALL; внешний "Normaliz.dll"; функция Normalize (const s: строка): строка; вар newLength: целое число; начать // в режиме NormalizationC строка результата не будет длиннее входной строки SetLength (Результат, Длина (с)); newLength: = NormalizeString (NormalizationC, PChar (s), Length (s), PChar (Result), Length (Result)); SetLength (Result, newLength); конец; function UnescapeAndNormalize (const s: AnsiString): строка; начать Результат: = нормализация (Unescape (s)); конец;
Спасибо вам всем! Я уверен, что мой первый опыт работы со Stackru не будет моим последним:-)
Они всегда так убегали? Всегда в количестве 4 цифр?
Как избежать \ самого персонажа?
Предполагая, что символ \ экранирован символом \ xxxx, где xxxx - это код символа \, вы можете легко перебрать строку:
function Unescape(s: AnsiString): WideString;
var
i: Integer;
j: Integer;
c: Integer;
begin
// Make result at least large enough. This prevents too many reallocs
SetLength(Result, Length(s));
i := 1; j := 1;
while i <= Length(s) do
begin
// If a '\' is found, typecast the following 4 digit integer to widechar
if s[i] = '\' then
begin
if (s[i+1] <> 'u') or not TryStrToInt(Copy(s, i+2, 4), c) then
raise Exception.CreateFmt('Invalid code at position %d', [i]);
Inc(i, 6);
Result[j] := WideChar(c);
end
else
begin
Result[j] := WideChar(s[i]);
Inc(i);
end;
Inc(j);
end;
// Trim result in case we reserved too much space
SetLength(Result, j-1);
end;
Используйте как это
MessageBoxW(0, PWideChar(Unescape('\u0252berhaupt')), nil, MB_OK);
Этот код протестирован в Delphi 2007, но также должен работать в XE из-за явного использования Ansistring и Widestring.
[править] Код в порядке. Маркер не работает.
Если я не ошибаюсь, Delphi XE теперь поддерживает регулярные выражения. Я не так часто их использую, но, похоже, это хороший способ разобрать строку и затем заменить все экранированные значения. Может быть, у кого-то есть хороший пример того, как сделать это в Delphi с помощью регулярных выражений?
GolezTrol, вы забыли '$'
if (s[i+1] <> 'u') or not TryStrToInt('$'+Copy(s, i+2, 4), c) then