Json parsing, generating and beautifiying / formatting with AutoHotkey?

♀尐吖头ヾ 提交于 2019-12-11 09:47:05

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!