hydrobyte / McJSON

A Delphi / Lazarus / C++Builder simple and small class for fast JSON parsing.
MIT License
58 stars 20 forks source link

Check function does not return the wrong position #18

Closed totyaxy closed 1 year ago

totyaxy commented 1 year ago

Hi!

I would like to use the check function, but the problem is that it hides the error position (without debugger).

function TMcJsonItem.Check(const aStr: string; aSpeedUp: Boolean): Boolean;
var
  aItem: TMcJsonItem;
begin
  aItem := TMcJsonItem.Create;
  try
    aItem.fSpeedUp := aSpeedUp;
    aItem.AsJSON   := aStr;
//    Result := True;
    Result := (aItem.AsJSON = trimWS(aStr));
  except
    Result := False;
  end;
  aItem.Free;
end;   

Idea, integer result:

function TMcJsonItem.Check(const aStr: string; aSpeedUp: Boolean): integer // return value is the wrong position...

and then the original function stay, and use it:

function TMcJsonItem.Check(const aStr: string; aSpeedUp: Boolean): booelan;
begin
  if Check(aStr, aSpeedup)<0 then Result:= true else Result:=false;
end;

... or other way, if you have time.

hydrobyte commented 1 year ago

Hi! Good idea! I'll implement these Check() variations into next commit. Thanks!

totyaxy commented 1 year ago

Thank you!

However, then the solution could be a bit more multifaceted, there could also be a LastErrorPos public variable. So the simple boolean version of Check could also be used. But I thought about this basically because during normal loading (LoadFromFile) an exception with the error position actually comes up, but it would be good to know the exact error position there as well. It would be good to process the error position programmatically, because "4500 error pos" does not say much to the user working in json. However, based on the position, I can show him a detail from the file (string) where the error is (part of the string that he can search for, possibly the line number).

These are only suggestions.

You can even the hand over the error in the exception (I'm sure you know how to do it, just an example, and I think the LastErrorPos class variable is simpler solution):

type
  EMcJsonException = class(Exception)
  public
    constructor Create(const msg: string; const aLastErrorPos: integer = -1);
  private
    FLastErrorPos: integer;
  public
    property LastErrorPos: integer read FLastErrorPos;
  end;

constructor EMcJsonException.Create(const msg: string; const aLastErrorPos: integer = -1);
begin
  inherited Create(msg);

  FLastErrorPos := aLastErrorPos;
end;            

usage:

procedure TForm1.Button1Click(Sender: TObject);
var
  s: string;
begin
  try
    raise EMcJsonException.Create('Damaged json', 1200);
  except
    on E: EMcJsonException do
    begin
      s := '"%s" Bad line count: "%d"';
      ShowMessage(Format(s, [E.Message, E.LastErrorPos]));
    end;
  end;
end;
totyaxy commented 1 year ago

Hi! Good idea! I'll implement these Check() variations into next commit. Thanks!

Hi!

I didn't see it in the next version, but it would be nice, indeed, thanks :)

totyaxy commented 1 year ago

H!

Thank you, I made a mistake in the json database file, and got an exception:

Error while parsing text: "line break" at pos "1051"

It is good. :) Because In my current use, the most common error is when the json structure is damaged.

The next step, if I got the bad number pos directly, whithout I need to parse(?) the E.Message (E.LastErrorPos see above?). So it should be separated from the error message, which could be a separate TException anyway.

Now SParsingErrors there are:

Thank you!

totyaxy commented 1 year ago

I temporarily solved the error position in the following way:

    try
      Result := Json.CheckException(JsonStr, True);
    except
      on E: Exception do
      begin
        Memo.Write('...Json database INVALID!');
        Memo.Write('Json library error message: '+E.Message);

        if UTF8Pos('at pos', E.Message)>0 then
        begin
          Memo.Write('');
          Memo.Write('You can jump to the error pos for example in Notepad++ : Search/Goto/Offset (Ctrl-G)');
        end;
      end;
    end;
hydrobyte commented 1 year ago

Nice solution.

totyaxy commented 1 year ago

"temporarily" solution :)

How much nicer would this be for example (see above):

on E: EMcJsonDamagedStructureException do
begin
  Memo.Write('Json damaged, positon: '+E.DamagedStructurePos');  
end;