【问题标题】:Delphi decode json/utf8 escaped textDelphi 解码 json/utf8 转义文本
【发布时间】:2012-03-31 14:13:32
【问题描述】:

我正在为复杂的应用程序编写一个模块,我的模块应该处理由 Web 服务器返回的 json 响应。所以,我的问题是如何解码这种文本:

\u041f\u043e\u0438\u0441\u043a \u043f\u043e \u0444\u0430\u043c\u0438\u043b\u0438\u0438, \u0438\u043c\u0435\u043d\u0438 (\u043e\u0442\u0447\u0435\u0441\u0442\u0432\u0443

这是西里尔文字,Mozilla Firefox 会按原样显示。我该如何处理这些家伙?我在 Delphi 2010 上。

【问题讨论】:

  • 您的 JSON 解码库应该已经为您处理好了。你在用什么图书馆?此外,这不是有效的 JSON;你确定这实际上不在字符串中吗?
  • 我没有使用一些 JSON 库得到这个。我只是使用“原始”HTTP GET 查询来获取它。
  • 我明白这一点,但是如果您收到的内容应该是 JSON 编码的,正如您所说的那样,那么您应该使用 JSON 解码库来处理它,而不是自己编写.
  • 这不是 UTF-8,而是包含转义 UTF-16 代码点的字符串。
  • 我看到了反斜杠、空格、数字、拉丁字母、逗号和括号,@User。都是 UTF-8 代码点。

标签: json delphi unicode escaping codepages


【解决方案1】:

如果有人需要简单的函数来解码 JSON 转义字符串:

function JSONUnescape(const Source: string; CRLF: string = #13#10): string;
const
  ESCAPE_CHAR = '\';
  QUOTE_CHAR = '"';
  EXCEPTION_FMT = 'Invalid escape at position %d';
var
  EscapeCharPos, TempPos: Integer;
  Temp: string;
  IsQuotedString: Boolean;
begin
  result := '';
  IsQuotedString := (Source[1] = QUOTE_CHAR) and
    (Source[Length(Source)] = QUOTE_CHAR);
  EscapeCharPos := Pos(ESCAPE_CHAR, Source);
  TempPos := 1;
  while EscapeCharPos > 0 do
  begin
    result := result + Copy(Source, TempPos, EscapeCharPos - TempPos);
    TempPos := EscapeCharPos;
    if EscapeCharPos < Length(Source) - Integer(IsQuotedString) then
      case Source[EscapeCharPos + 1] of
        't':
          Temp := #9;
        'n':
          Temp := CRLF;
        '\':
          Temp := '\';
        '"':
          Temp := '"';
        'u':
          begin
            if EscapeCharPos + 4 < Length(Source) - Integer(IsQuotedString) then
              Temp := Chr(StrToInt('$' + Copy(Source, EscapeCharPos + 2, 4)))
            else
              raise Exception.Create(Format(EXCEPTION_FMT, [EscapeCharPos]));
            Inc(TempPos, 4);
          end;
      else
        raise Exception.Create(Format(EXCEPTION_FMT, [EscapeCharPos]));
      end
    else
      raise Exception.Create(Format(EXCEPTION_FMT, [EscapeCharPos]));
    Inc(TempPos, 2);
    result := result + Temp;
    EscapeCharPos := Pos(ESCAPE_CHAR, Source, TempPos);
  end;
  result := result + Copy(Source, TempPos, Length(Source) - TempPos + 1);
end;

用法:

JSONUnescape('\u2764Love Delphi\u2764');
// Returns '❤Love Delphi❤'
JSONUnescape('"\u2764Love\tDelphi\u2764"');
// Returns '"❤Love  Delphi❤"';
JSONUnescape('\\\Invalid escaped text');
// Raises and exception 'Invalid escape at position 3'

【讨论】:

    【解决方案2】:

    您可以使用 Delphi 2010 中包含的 DBXJSON 单元

    uses
     DBXJSON;
    
    const
    JsonUt8  ='"\u041f\u043e\u0438\u0441\u043a \u043f\u043e \u0444\u0430\u043c\u0438\u043b\u0438\u0438, \u0438\u043c\u0435\u043d\u0438 (\u043e\u0442\u0447\u0435\u0441\u0442\u0432\u0443"';
    
    procedure TForm59.Button1Click(Sender: TObject);
    var
      LJSONValue: TJSONValue;
    begin
      LJSONValue:=TJSONObject.ParseJSONValue(TEncoding.UTF8.GetBytes(JsonUt8),0);
      Edit1.Text:=LJSONValue.ToString;
    end;
    

    【讨论】:

    • 看起来不错,谢谢。也许,我应该去那个图书馆。
    【解决方案3】:

    好的,伙计们,这里有完整的代码可以帮助我解决这个问题:

    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: PWideChar; cwSrcLength: Integer;
     lpDstString: PWideChar; 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;
    

    代码是从this answer盗取的

    【讨论】:

    • 有没有办法可以在 D2007 中实现?缺少 unicode 会在哪里阻止这种情况?
    猜你喜欢
    • 2017-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-31
    • 1970-01-01
    • 2019-11-02
    • 1970-01-01
    相关资源
    最近更新 更多