Funny you said that, cuz I got bored and that's exactly what I did lol (among other trivial things)
I did make the indentation (this.Space) loop run only when !_d and gave it a static variable, other than that, I made fthrow method cuz I hate commands!
Also replaced SmartR8 with format("{:g}", v), but I imagine you probably want something more robust?
Code: Select all
class json {
;json.set by vvhitevvizard. json.get by coco and modified by vvhitevvizard
get(ByRef _s) { ;obj:=json.get(str)
static q:=Chr(34), p:={"__Arr":1} ,x:=q "{[0123456789-" ;json allowed chars outside strings
n:=0, k:="",kf:=0, s:=[root:={}], z:="{"
while (c:=SubStr(_s, ++n, 1))!=="" {
if InStr(" `t`n`r", c)
continue
InStr(z, c) || E(c, n), a:=(b:=s.1).__Arr
if InStr("}]", c) {
(s.1=root) && E(c, n), s.RemoveAt(1), z:=s.1.__Arr ? ",]" : ",}"
} else if InStr(",:", c) {
z:=(kf:=!a && c==",") ? q : x
} else if InStr("{[", c) {
(c=="{") ? (kf:=1, v:={}, z:=q "}") : (v:=new p, z:=x "]"), s.InsertAt(1,v)
,a ? k:=b.Push(v) : b[k]:=v
} else {
if c==q { ;string literals
v:=SubStr(_s, n+1, InStr(_s,q,, n+1)-n-1), n += StrLen(v)+1
if kf {
k:=v, z:=":"
continue
}
} else { ;number
v:=SubStr(_s, n, (SubStr(_s, n) ~= "[\]\},\s]|$")-1), n += StrLen(v)-1
,(v is "Number") ? v += 0 : this.E(c, n)
}
a ? k:=b.Push(v) : b[k]:=v, z := a ? ",]" : ",}"
}
}
return (s.1==root || this.E(c, n), b) ;s.Count()!=1 ;unpaired {}, []
E(_c,_n) => this.fthrow(Exception("Unexpected char <" _c "> in pos " _n, -1))
}
;"stringify": format [associative] array (object) as JSON string: str:=json.set(obj)
;by vvhitevvizard
;0=enable indentation and line feed, 1=the most compact representation:
static Compact:=0
;spaces per level, similar to JavaScript's JSON.stringify() 'space' parameter
; JSON array elements and object members will be pretty-printed with the indent level:
static Space:=4
;0=suppress error on built-in object types, just output a class name, e.g.: "File Object":
static ErrObjType:=0
;0=supress error if the root is not an object:
static ErrObj:=0
set(_o, _d:="") { ;_d:current indent
if !IsObject(_o) ;"string" | number
return this.ErrObj && this.fthrow(Exception("Not an object.", -1))
static q:= Chr(34), ind
(_d) || ind := indent(this.Space), (this.Compact) ? n:=d:="" : n:="`n", d:=_d ind
,VarSetCapacity(s,1024*8)
;Check object type, skipping of non-serializable objects such as COM, Func, BoundFunc, File, etc
; otherwise we get "Unknown method _NewEnum" for loop:
try a:=_o.__Arr ;trying to get a unique key
catch ;"Unknown property" exception means its a built-in inenumerable object
return (t:=Type(_o) " Object"
, (this.ErrObjType) && this.fthrow(Exception(t " type is not supported.", -1))
, "{" q t q "}")
;due to the use of a for-loop, arrays such as '[1,,3]' are detected as objects({})
for i in _o
if !(a:=i=A_Index) ;a=0:associative or sparse array ([1,,3])
break
for k, v in _o ;recursive
;JSON standard: keys are always "strings", values r: number|"string"|{object}|[array]
s .= d (a ? "" : q k q ":") (isObject(v) ? this.set(v, d)
: (Type(v)=="String") ? q v q
: (Type(v)=="Float") ? format("{:g}", v)
: v) "," n
return (a ? "[" : "{") (s ? (n RTrim(s, "," n) n _d) : "") (a ? "]" : "}") ;wrap to brackets
indent(n) {
loop(n)
_ .= " "
return _
}
}
fthrow(e) {
throw e
}
}
Dump(_s, _z:="") { ;dump text to file with random name
f:=FileOpen(_z ? _z:A_TickCount,"w"), n:=f.Write(_s)
f.Close() ;also flushes any data in the cache to disk and releases the share locks
return n
}
j:='{"r1":{"r2":{"type1":11,"type2":11},"misc":12}, "type":"ask","price":104.2,"amount":101, "a":[111,"aa"]}'
if(0) {
j:=FileRead("1678982546")
b:=json.get(j)
s:=json.set(b)
if(j==s)
msgbox("in=out")
else
Dump(s, "out")
}
else {
loop(5000)
b:=json.get(j)
t:=A_TickCount
loop(20000)
b:=json.get(j)
a1:=A_TickCount-t
t:=A_TickCount
loop(20000)
s:=json.set(b)
a2:=A_TickCount-t
msgbox(clipboard:=a1 "|" a2 "`n`n" s)
}