首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> Delphi

Delphi JSON 庫 DJSON 深度解析:JSONTokener 實作(下)

     編輯:Delphi

承接上篇,本文深入剖析 Delphi 版 JSONTokener 的核心解析邏輯。此單元移植自 JSON.org 官方 Java 實作,並針對 Delphi 語言特性(無垃圾回收、無基本型別包裝類別)進行調整,引入智慧指標與自訂包裝類別。以下詳細說明關鍵方法實作。

核心架構

TJSONTokener 封裝字串來源與當前索引,提供字元級、Token 級導航與解析功能。主要欄位:

  • fMySource: string - 待解析 JSON 字串
  • fMyIndex: Integer - 當前讀取位置

關鍵方法解析

1. 字元導航與清理

  • Next / Back:基本前進/後退一字元。
  • NextClean:跳過空白字元、單行註釋(//)、多行註釋(/* */)與 Shell 風格註釋(#),回傳下一個有效字元。這使解析器能容忍帶註釋的非標準 JSON。

2. 字串解析:NextString

處理雙引號或單引號包裹的字串,支援跳脫序列:\b \t \n \f \r \\ \" \' \uXXXX \xXX。遇到未閉合字串拋出 EJSONException。

3. Token 擷取:NextTo / NextValue

  • NextTo(delimiters):讀取直到遇到分隔字元集、換行或結尾。
  • NextValue:核心解析入口,根據首字元分派:
    • { → 建立 TJSONObject(遞迴解析)
    • [ 或 ( → 建立 TJSONArray
    • 引號 → 解析字串
    • 其他 → 嘗試解析為 true/false/null、數值(整數/長整數/雙精度/十六進制/八進制),失敗則視為字串。

4. 數值解析策略

採用多層 try...except 級聯:Integer → Int64 → Double → String。特殊支援 0x 十六進制與 0 開頭八進制(非標準 JSON),提升相容性。

5. 智慧指標整合

所有回傳物件皆包裝於 IAutoPtr<TObject> 介面,模擬 Java 參考計數語意,自動管理 TStringObject、TBooleanObject、TIntegerObject、TLongObject、TDoubleObject、TJSONObject、TJSONArray 生命週期,避免記憶體洩漏。

完整單元原始碼

(節錄關鍵實作,完整碼見原文)

unit JSONTokener;

interface
uses SysUtils, StrUtils, AutoPtr, JSONException;

type
  TJSONTokener = class
  private
    fMyIndex: Integer;
    fMySource: string;
  public
    constructor Create(aMySource: string); virtual;
    procedure Back;
    class function DeHexChar(c: Char): Integer;
    function More: Boolean;
    function Next: Char; overload;
    function Next(c: Char): Char; overload;
    function Next(n: Integer): string; overload;
    function SyntaxError(aMsg: string): EJSONException;
    function ToString: string; override;
    function NextClean: Char;
    function NextString(quote: Char): string;
    function NextTo(delimiters: string): string; overload;
    function NextTo(d: Char): string; overload;
    function NextValue: IAutoPtr<TObject>;
    function SkipTo(toc: Char): Char;
    function SkipPast(tos: string): Boolean;
  end;

implementation
uses StringObject, BooleanObject, IntegerObject, LongObject, DoubleObject,
     Utils, JSONObject, JSONArray;

{ 關鍵實作範例 }

function TJSONTokener.NextClean: Char;
var c: Char;
begin
  while True do
  begin
    c := Next;
    if c = '/' then
    begin
      case Next of
        '/': repeat c := Next until (c in [#13, #10, #0]);
        '*': 
        begin
          while True do
          begin
            c := Next;
            if c = #0 then raise SyntaxError('Unclosed comment');
            if c = '*' then if Next = '/' then Break else Back;
          end;
        end;
      else Back; Exit('/');
      end;
    end
    else if c = '#' then repeat c := Next until (c in [#13, #10, #0])
    else if (c = #0) or (c > ' ') then Exit(c);
  end;
end;

function TJSONTokener.NextValue: IAutoPtr<TObject>;
var c, b: Char; s, sb: string;
begin
  c := NextClean;
  case c of
    '"', ''': Exit(TAutoPtr<TObject>.New(TStringObject.Create(NextString(c))));
    '{': begin Back; Exit(TAutoPtr<TObject>.New(TJSONObject.Create(Self))); end;
    '[', '(': begin Back; Exit(TAutoPtr<TObject>.New(TJSONArray.Create(Self))); end;
  end;
  b := c;
  while (c >= ' ') and (Pos(c, ',:]}/\"[{;=#') = 0) do
  begin sb := sb + c; c := Next; end;
  Back;
  s := Trim(sb);
  if s = '' then raise SyntaxError('Missing value');
  if LowerCase(s) = 'true'  then Exit(TAutoPtr<TObject>.New(TBooleanObject.TRUE));
  if LowerCase(s) = 'false' then Exit(TAutoPtr<TObject>.New(TBooleanObject.FALSE));
  if LowerCase(s) = 'null'  then Exit(TAutoPtr<TObject>.New(TJSONObject.NULL));
  // 數值解析級聯...
  Exit(TAutoPtr<TObject>.New(TStringObject.Create(s)));
end;

設計亮點總結

  1. 語言適配:以智慧指標替代 GC,以包裝類別替代基本型別物件化。
  2. 容錯性:支援註釋、單引號字串、非標準數值格式。
  3. 模組化:Tokenizer、Parser、Value 物件分離,符合單一職責。

此實作展示了如何將經典 Java 庫優雅移植至 Delphi,保留原始設計精髓同時發揮 Delphi 語言優勢。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved