david_navigator 12 Posted March 8, 2023 (edited) I have some code that I inherited from someone else which is used to convert a dataset to JSON. Mostly it works OK, but rather than a £ being converted to \u00A3 it gets converted to \\u00A3 i.e the slash gets escaped again. So from "Additional Fuel Used 170 Litres @ £2.00 per Litre" rather than "Additional Fuel Used 170 Litres @ \u00A32.00 per Litre" I get "Additional Fuel Used 170 Litres @ \\u00A32.00 per Litre" I've found very similar code in StackOverflow, but that has the same issue. This is the SO code as it's potentially easier to read. Can anyone point out where I/they are going wrong please ? As far as I can tell the EscapeValue code is correctly converting the £ to \u00A3, but then the TJSONPair.create seems to be then re-escaping the one '\' in to '\\' unit Unit71; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, dbxjson, json; type TForm71 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; type TSvJsonString = class(TJSONString) private function EscapeValue(const AValue: string): string; public constructor Create(const AValue: string); overload; end; var Form71: TForm71; implementation {$R *.dfm} 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 TForm71.Button1Click(Sender: TObject); var LText, LEscapedText: string; LJsonString: TSvJsonString; LJsonPair: TJsonPair; LJsonObject: TJsonObject; begin LText := 'The price is £20.00'; LJsonString := TSvJsonString.Create(LText); LJsonPair := TJsonPair.Create('MyString', LJsonString); LJsonObject := TJsonObject.Create(LJsonPair); try LEscapedText := LJsonObject.ToString; showmessage(LEscapedText); LEscapedText := LJsonObject.ToJSON; showmessage(LEscapedText); finally LJsonObject.Free; end; end; end. Edited March 8, 2023 by david_navigator Share this post Link to post
Der schöne Günther 316 Posted March 8, 2023 None of this should be necessary. Just using a regular TJsonString outputs {"MyString":"The price is £20.00"} {"MyString":"The price is \u00A320.00"} Check: program Project1; uses System.JSON; var LText, LEscapedText: string; LJsonString: TJsonString; LJsonPair: TJsonPair; LJsonObject: TJsonObject; begin LText := 'The price is £20.00'; LJsonString := TJsonString.Create(LText); // Not your subclass TSvJsonString LJsonPair := TJsonPair.Create('MyString', LJsonString); LJsonObject := TJsonObject.Create(LJsonPair); try LEscapedText := LJsonObject.ToString; WriteLn(LEscapedText); LEscapedText := LJsonObject.ToJSON; WriteLn(LEscapedText); finally LJsonObject.Free; end; ReadLn; end. Share this post Link to post
david_navigator 12 Posted March 8, 2023 Quote None of this should be necessary. Just using a regular TJsonString outputs Many thanks. Don't I feel stupid !! Now to do some experimenting to see if all the characters in the above routine get escaped correctly automatically . Share this post Link to post
Der schöne Günther 316 Posted March 9, 2023 14 hours ago, david_navigator said: do some experimenting to see Don't experiment and then forget about it. Write some proper unit tests so that they will always be with you and your project. 🧐 Share this post Link to post
David Heffernan 2345 Posted March 9, 2023 Do pound signs need to be escaped in json? Please tell me you are using Unicode. Share this post Link to post
Lars Fosdal 1792 Posted March 9, 2023 No. PS C:\Users\foslar> '£'|ConvertTo-Json "£" Share this post Link to post
renna 0 Posted April 4, 2023 A JSON string must be double-quoted, according to the specs, so you don't need to escape '. If you have to use special character in your JSON string, you can escape it using \ character. Share this post Link to post