gpt4 book ai didi

json - 如何使用 DBXJSON 将字符串与带有转义/特殊字符的 JSON 相互转换?

转载 作者:行者123 更新时间:2023-12-03 14:37:07 28 4
gpt4 key购买 nike

我在将带有转义字符的字符串转换为 TJsonString 转换时遇到问题。 (我使用的是 Delphi XE 2、Update 4、Hotfix 1)。

注意:我熟悉 SuperObject ,但我的要求是使用 DBXJSON 单元。

通过 ToString() 方法返回 JSON 表示形式时,TJSONString 似乎未正确转义。

我做错了什么(如果有的话)以及如何正确地将带有特殊字符的字符串转换为正确的 JSON 表示形式?

也许我错过了一些东西,但以下问答似乎都没有直接解决这个问题:

EDIT:

As it turns out, the examples below were indeed working as expected.

What wasn't clear to me was that when creating a TJSONString via it's constructor and adding it to a TJSONObject, the ToString() method will return an escaped representation. However, after parsing a TJSONObject, the ToString() method will returned the un-escaped representation.

The only other caveat was that the EscapeString() function in the sample code below was handling the double-quote. Although I wasn't using the double quote here, some of my other code was, and that caused the parsing to fail because TJSONString already escapes that character. I've updated my sample code to remove this handling from the EscapeString() function, which is what I've been using in my own classes.

Thanks again to @Linas for the answer, which helped me to "get" it.

原始字符串值:

Text := 'c:\path\name' +#13 + #10 + 'Next Line';

Text: c:\path\name
Next Line

DBXJSON 生成什么(无转义):

JsonString: "c:\path\name
Next Line"

JsonPair: "MyString":"c:\path\name
Next Line"

JsonObject: {"MyString":"c:\path\name
Next Line"}

解析非转义文本失败:

Text to parse: {"MyString":"c:\path\name
Next Line"}

Parsed JsonObject = *NIL*

期望 DBXJSON 生成什么:

Escaped String: c:\\path\\name\r\nNext Line

JsonString: "c:\\path\\name\r\nNext Line"

JsonPair: "MyString":"c:\\path\\name\r\nNext Line"

JsonObject: {"MyString":"c:\\path\\name\r\nNext Line"}

解析转义文本(无效)(要解析的文本已通过 JSONLint 进行验证):

Text to parse: {"MyString":"c:\\path\\name\r\nNext Line"}

Parsed JsonObject.ToString(): {"MyString":"c:\path\name
Next Line"}

我注意到 TJSONString 唯一能正确处理的特殊字符是双引号 (")。

这是我正在使用的代码:

program JsonTest;

{$APPTYPE CONSOLE}

{$R *.res}

uses
System.SysUtils, DbxJson;

function EscapeString(const AValue: string): string;
const
ESCAPE = '\';
// QUOTATION_MARK = '"';
REVERSE_SOLIDUS = '\';
SOLIDUS = '/';
BACKSPACE = #8;
FORM_FEED = #12;
NEW_LINE = #10;
CARRIAGE_RETURN = #13;
HORIZONTAL_TAB = #9;
var
AChar: Char;
begin
Result := '';
for AChar in AValue do
begin
case AChar of
// !! Double quote (") is handled by TJSONString
// QUOTATION_MARK: Result := Result + ESCAPE + QUOTATION_MARK;
REVERSE_SOLIDUS: Result := Result + ESCAPE + REVERSE_SOLIDUS;
SOLIDUS: Result := Result + ESCAPE + SOLIDUS;
BACKSPACE: Result := Result + ESCAPE + 'b';
FORM_FEED: Result := Result + ESCAPE + 'f';
NEW_LINE: Result := Result + ESCAPE + 'n';
CARRIAGE_RETURN: Result := Result + ESCAPE + 'r';
HORIZONTAL_TAB: Result := Result + ESCAPE + 't';
else
begin
if (Integer(AChar) < 32) or (Integer(AChar) > 126) then
Result := Result + ESCAPE + 'u' + IntToHex(Integer(AChar), 4)
else
Result := Result + AChar;
end;
end;
end;
end;

procedure Test;
var
Text: string;
JsonString: TJsonString;
JsonPair: TJsonPair;
JsonObject: TJsonObject;
begin
try
Writeln('Raw String Value');
Writeln('-----------------');
Text := 'c:\path\name' +#13 + #10 + 'Next Line';
Writeln('Text: ', Text);
JsonString := TJsonString.Create(Text);
JsonPair := TJsonPair.Create('MyString', JsonString);
JsonObject := TJsonObject.Create(JsonPair);
// DBXJSON results
Writeln;
Writeln('What DBXJSON produces');
Writeln('---------------------');
Writeln('JsonString: ', JsonString.ToString);
Writeln;
Writeln('JsonPair: ', JsonPair.ToString);
Writeln;
Writeln('JsonObject: ', JsonObject.ToString);
Writeln;

// assign JSON representation
Text := JsonObject.ToString;
// free json object
JsonObject.Free;
// parse it
JsonObject:= TJsonObject.ParseJsonValue(TEncoding.ASCII.GetBytes(
Text), 0) as TJsonObject;
Writeln('Parsing UN-escaped Text *FAILS* ');
Writeln('----------------------------------');
Writeln('Text to parse: ', Text);
Writeln;
if (JsonObject = nil) then
Writeln('Parsed JsonObject = *NIL*')
else
Writeln('Parsed JsonObject: ', JsonObject.ToString);
Writeln;
// free json object
JsonObject.Free;
// expected results
Text := 'c:\path\name' +#13 + #10 + 'Next Line';
Text := EscapeString(Text);
JsonString := TJsonString.Create(Text);
JsonPair := TJsonPair.Create('MyString', JsonString);
JsonObject := TJsonObject.Create(JsonPair);
Writeln('What I *EXPECT* DBXJSON to produce');
Writeln('----------------------------------');
Writeln('Escaped String: ', Text);
Writeln;
Writeln('JsonString: ', JsonString.ToString);
Writeln;
Writeln('JsonPair: ', JsonPair.ToString);
Writeln;
Writeln('JsonObject: ', JsonObject.ToString);
Writeln;
// assign JSON representation
Text := JsonObject.ToString;
// free json object
JsonObject.Free;
// parse it
JsonObject:= TJsonObject.ParseJsonValue(TEncoding.ASCII.GetBytes(
Text), 0) as TJsonObject;
Writeln('Parsing ESCAPED Text (*INVALID*) ');
Writeln('----------------------------------');
Writeln('Text to parse: ', Text);
Writeln;
Writeln('Parsed JsonObject.ToString(): ', JsonObject.ToString);
Writeln;
Readln;
except
on E: Exception do
begin
Writeln(E.ClassName, ': ', E.Message);
Readln;
end;
end;
end;

begin
Test;
end.

最佳答案

您可以尝试定义自己的 TJSONString 类型并在那里转义 json 字符串。例如:

uses
DBXJSON;

type
TSvJsonString = class(TJSONString)
private
function EscapeValue(const AValue: string): string;
public
constructor Create(const AValue: string); overload;
end;

{ TSvJsonString }

constructor TSvJsonString.Create(const AValue: string);
begin
inherited Create(EscapeValue(AValue));
end;

function TSvJsonString.EscapeValue(const AValue: string): string;

procedure AddChars(const AChars: string; var Dest: string; var AIndex: Integer); inline;
begin
System.Insert(AChars, Dest, AIndex);
System.Delete(Dest, AIndex + 2, 1);
Inc(AIndex, 2);
end;

procedure AddUnicodeChars(const AChars: string; var Dest: string; var AIndex: Integer); inline;
begin
System.Insert(AChars, Dest, AIndex);
System.Delete(Dest, AIndex + 6, 1);
Inc(AIndex, 6);
end;

var
i, ix: Integer;
AChar: Char;
begin
Result := AValue;
ix := 1;
for i := 1 to System.Length(AValue) do
begin
AChar := AValue[i];
case AChar of
'/', '\', '"':
begin
System.Insert('\', Result, ix);
Inc(ix, 2);
end;
#8: //backspace \b
begin
AddChars('\b', Result, ix);
end;
#9:
begin
AddChars('\t', Result, ix);
end;
#10:
begin
AddChars('\n', Result, ix);
end;
#12:
begin
AddChars('\f', Result, ix);
end;
#13:
begin
AddChars('\r', Result, ix);
end;
#0 .. #7, #11, #14 .. #31:
begin
AddUnicodeChars('\u' + IntToHex(Word(AChar), 4), Result, ix);
end
else
begin
if Word(AChar) > 127 then
begin
AddUnicodeChars('\u' + IntToHex(Word(AChar), 4), Result, ix);
end
else
begin
Inc(ix);
end;
end;
end;
end;
end;

使用示例:

procedure Test;
var
LText, LEscapedText: string;
LJsonString: TSvJsonString;
LJsonPair: TJsonPair;
LJsonObject: TJsonObject;
begin
LText := 'c:\path\name' + #13 + #10 + 'Next Line';
LJsonString := TSvJsonString.Create(LText);
LJsonPair := TJsonPair.Create('MyString', LJsonString);
LJsonObject := TJsonObject.Create(LJsonPair);
try
LEscapedText := LJsonObject.ToString;
//LEscapedText is: c:\\path\\name\r\nNext Line
finally
LJsonObject.Free;
end;
end;

这就是解析的方式:

//AText := '{"MyString":"c:\\path\\name\r\nNext Line"}';
function Parse(const AText: string): string;
var
obj: TJSONValue;
begin
obj := TJSONObject.ParseJSONValue(AText);
try
Result := obj.ToString;
//Result := {"MyString":"c:\path\name
//Next Line"}
finally
obj.Free;
end;
end;

关于json - 如何使用 DBXJSON 将字符串与带有转义/特殊字符的 JSON 相互转换?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11785963/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com