问题
How to convert a json string into autohotkey objects/arrays... and the other way around? And how to get the json string nicely formatted with newline characters and space indentations?
回答1:
Here is a Json class I wrote recently. It automatically handles indentation and newline chars. You can even specify which characters to use etc.
And it also handles edge cases like double quotes within strings (they need to be escaped in json), that's something I was really missing from other json functions in ahk.
class Json {
__New(indent=" ",newLine="`r`n") { ;default indent: 4 spaces. default newline: crlf
this.ind := indent
this.nl := newLine
}
getIndents(num) {
indents := ""
Loop % num
indents .= this.ind
Return indents
}
jsonFileToObj(fileFullPath) {
file := FileOpen(fileFullPath, "r")
Return this.jsonToObj(file.Read()), file.Close()
}
objToJsonFile(obj,fileFullPath) {
FileDelete, % fileFullPath
SplitPath, fileFullPath,, dir
FileCreateDir % dir
file := FileOpen(fileFullPath, "w")
Return file.write(this.objToJson(obj)), file.Close()
}
objToJson(obj,indNum:=0) {
indNum++
str := "" , array := true
for k in obj {
if (k == A_Index)
continue
array := false
break
}
for a, b in obj
str .= this.getIndents(indNum) . (array ? "" : """" a """: ") . (IsObject(b) ? this.objToJson(b,indNum) : this.isNumber(b) ? b : """" StrReplace(b,"""","\""") """") . ", " this.nl
str := RTrim(str, " ," this.nl)
return (array ? "[" this.nl str this.nl this.getIndents(indNum-1) "]" : "{" this.nl str this.nl this.getIndents(indNum-1) "}")
}
jsonToObj(jsonStr) {
SC := ComObjCreate("ScriptControl")
SC.Language := "JScript"
ComObjError(false)
jsCode =
(
function arrangeForAhkTraversing(obj) {
if(obj instanceof Array) {
for(var i=0 ; i<obj.length ; ++i)
obj[i] = arrangeForAhkTraversing(obj[i]) ;
return ['array',obj] ;
} else if(obj instanceof Object) {
var keys = [], values = [] ;
for(var key in obj) {
keys.push(key) ;
values.push(arrangeForAhkTraversing(obj[key])) ;
}
return ['object',[keys,values]] ;
} else
return [typeof obj,obj] ;
}
)
SC.ExecuteStatement(jsCode "; obj=" jsonStr)
return this.convertJScriptObjToAhkObj( SC.Eval("arrangeForAhkTraversing(obj)") )
}
convertJScriptObjToAhkObj(jsObj) {
if(jsObj[0]="object") {
obj := {}, keys := jsObj[1][0], values := jsObj[1][1]
loop % keys.length
obj[keys[A_INDEX-1]] := this.convertJScriptObjToAhkObj( values[A_INDEX-1] )
return obj
} else if(jsObj[0]="array") {
array := []
loop % jsObj[1].length
array.insert(this.convertJScriptObjToAhkObj( jsObj[1][A_INDEX-1] ))
return array
} else
return jsObj[1]
}
isNumber(Num) {
if Num is number
return true
else
return false
}
}
List of methods:
json.jsonFileToObj(fileFullPath) ;convert a json file into an ahk object
json.objToJsonFile(obj,fileFullPath) ;convert an ahk object into a json file
json.objToJson(obj) ;convert an object into a json string
json.jsonToObj(jsonStr) ;convert a json string into an ahk object
Example:
json := new Json(" ", "`r`n") ;use 2 space indentation and CR LF for new lines
testObject := {"key":"","key2":"val2",keyWithoutQuotes:"val3","myArray":["a1","a2","a3",{"myEdgeCase":"edge case ""test""","numberValue":2}]}
MsgBox % json.objToJson(testObject)
Output:
{
"key": "",
"key2": "val2",
"keyWithoutQuotes": "val3",
"myArray": [
"a1",
"a2",
"a3",
{
"myEdgeCase": "edge case \"test\"",
"numberValue": 2
}
]
}
And alternatively there is Coco's Json Class, you should definitely check it out. It may be 4 times more code, but it really has some interesting features.
回答2:
I use following function, works perfectly for me so far. No file handling, but determines direction by itself:
json(i)
{
;ENCODE
if (isobject(i))
{
o := "", a := 1, x := 1
for k,v in i
{
if (k!=x)
a := 0, break
x += 1
}
o .= (a) ? "[" : "{", f := 1
for k,v in i
o .= ((f) ? "" : ",")((a) ? "" : """" k """:")((isobject(v)) ? json(v) : ((v+0=v) ? v : """" v """")), f := 0
return o ((a) ? "]" : "}")
}
;DECODE
if (regexmatch(i, "s)^__chr(A|W):(.*)", m))
{
VarSetCapacity(b, 4, 0), NumPut(m2, b, 0, "int")
return StrGet(&b, 1, (m1="A") ? "cp28591" : "utf-16")
}
if (regexmatch(i, "s)^__str:((\\""|[^""])*)", m))
{
str := m1
for p,r in {b:"`b", f:"`f", n:"`n", 0:"", r:"`r", t:"`t", v:"`v", "'":"'", """":"""", "/":"/"}
str := regexreplace(str, "\\" p, r)
while (regexmatch(str, "s)^(.*?)\\x([0-9a-fA-F]{2})(.*)", m))
str := m1 json("__chrA:0x" m2) m3
while (regexmatch(str, "s)^(.*?)\\u([0-9a-fA-F]{4})(.*)", m))
str := m1 json("__chrW:0x" m2) m3
while (regexmatch(str, "s)^(.*?)\\([0-9]{1,3})(.*)", m))
str := m1 json("__chrA:" m2) m3
return regexreplace(str, "\\\\", "\")
}
str := [], obj := []
while (RegExMatch(i, "s)^(.*?[^\\])""((\\""|[^""])*?[^\\]|)""(.*)$", m))
str.insert(json("__str:" m2)), i := m1 "__str<" str.maxIndex() ">" m4
while (RegExMatch(RegExReplace(i, "\s+", ""), "s)^(.*?)(\{|\[)([^\{\[\]\}]*?)(\}|\])(.*)$", m))
{
a := (m2="{") ? 0 : 1, c := m3, i := m1 "__obj<" ((obj.maxIndex()+1) ? obj.maxIndex()+1 : 1) ">" m5, tmp := []
while (RegExMatch(c, "^(.*?),(.*)$", m))
tmp.insert(m1), c := m2
tmp.insert(c), tmp2 := {}, obj.insert(cobj := {})
for k,v in tmp
{
if (RegExMatch(v, "^(.*?):(.*)$", m))
tmp2[m1] := m2
else
tmp2.insert(v)
}
for k,v in tmp2
{
for x,y in str
k := RegExReplace(k, "__str<" x ">", y), v := RegExReplace(v, "__str<" x ">", y)
for x,y in obj
v := RegExMatch(v, "^__obj<" x ">$") ? y : v
cobj[k] := v
}
}
return obj[obj.maxIndex()]
}
source
来源:https://stackoverflow.com/questions/33989042/json-parsing-generating-and-beautifiying-formatting-with-autohotkey