Delphi XE AnsiStrings с экранированным сочетанием диакритических знаков
Как лучше всего преобразовать Delphi XE AnsiString, содержащий экранированное сочетание диакритических знаков, таких как" Fuu0308rst", в frienly WideString"Fürst"?
Я знаю, что это не всегда возможно для всех комбинаций, но общие латинские блоки должны поддерживаться без создания глупых таблиц преобразования самостоятельно. Я думаю, что решение можно найти где-то в блоке новых персонажей, но я его не понимаю.5 ответов:
Я думаю, что вам нужно выполнить нормализацию Юникода . на вашей струне.
Я не знаю, есть ли конкретный вызов в Delphi XE RTL, чтобы сделать это, но вызов WinAPI NormalizeString должен помочь вам здесь, с mode NormalizationKC:
NormalizationKC
Unicode normalization form KC, compatibility composition. Трансформация каждая база плюс комбинирование символов для канонический предварительно составленный эквивалент и все характеры совместимости к их аналог. Например, лигатуры Fi станет ф + я; аналогично, + + фи + N становится Ä + ж + я + н.
Вот полный код, который решил мою проблему:
function Unescape(const s: AnsiString): string; 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 s[i] = '\' then begin if i < Length(s) then begin // escaped backslash? if s[i + 1] = '\' then begin Result[j] := '\'; inc(i, 2); end // convert hex number to WideChar else if (s[i + 1] = 'u') and (i + 1 + 4 <= Length(s)) and TryStrToInt('$' + string(Copy(s, i + 2, 4)), c) then begin inc(i, 6); Result[j] := WideChar(c); end else begin raise Exception.CreateFmt('Invalid code at position %d', [i]); end; end else begin raise Exception.Create('Unexpected end of string'); end; 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; const NormalizationC = 1; function NormalizeString(NormForm: Integer; lpSrcString: LPCWSTR; cwSrcLength: Integer; lpDstString: LPWSTR; cwDstLength: Integer): Integer; stdcall; external 'Normaliz.dll'; function Normalize(const s: string): string; var newLength: integer; begin // in NormalizationC mode the result string won't grow longer than the input string SetLength(Result, Length(s)); newLength := NormalizeString(NormalizationC, PChar(s), Length(s), PChar(Result), Length(Result)); SetLength(Result, newLength); end; function UnescapeAndNormalize(const s: AnsiString): string; begin Result := Normalize(Unescape(s)); end;Спасибо вам всем! Я уверен, что мой первый опыт работы со StackOverflow не будет последним: -)
Они всегда так убегают? Всегда в количестве 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.
[edit] код в порядке. Маркер не работает.
Если я не ошибаюсь, Delphi XE теперь поддерживает регулярные выражения. Я не использую их так часто, но это кажется хорошим способом проанализировать строку и затем заменить все экранированные значения. Может быть, у кого-то есть хороший пример того, как это сделать в Delphi с регулярными выражениями?