Need help about Associative Arrays
Need help about Associative Arrays
This code return right data:
Test := {"name":"Baal","age":"50"}
MsgBox % Test.name "age" Test.age
I have some data is like this {"name":"Baal","age":"50"} ,this data in a Variables named DATA. but this code can't return right data:
DATA := "{""name"":""Baal"",""age"":""50""}"
Test := DATA
MsgBox % Test.name "age" Test.age
what wrong? how to convert my data to Associative Arrays
Test := {"name":"Baal","age":"50"}
MsgBox % Test.name "age" Test.age
I have some data is like this {"name":"Baal","age":"50"} ,this data in a Variables named DATA. but this code can't return right data:
DATA := "{""name"":""Baal"",""age"":""50""}"
Test := DATA
MsgBox % Test.name "age" Test.age
what wrong? how to convert my data to Associative Arrays
Re: Need help about Associative Arrays
Try this:
I hope that helps.
Code: Select all
DATA := {name: "Baal", age: 50}
Test := DATA
MsgBox % Test.name " age " Test.age
-
- Posts: 4412
- Joined: 29 Mar 2015, 09:41
- Contact:
Re: Need help about Associative Arrays
Since your data is in proper JSON format, you could using any JSON parsing code to convert such string to an AHK object. One of the approaches is using JScript for this purpose.Bral wrote:I have some data is like this {"name":"Baal","age":"50"} ,this data in a Variables named DATA.
Code: Select all
DATA := "{""name"":""Baal"",""age"":""50""}"
Test := JSON.Parse(DATA)
MsgBox, % Test.name . "`n" . Test.age
class JSON
{
static JS := JSON._GetJScripObject()
Parse(JsonString) {
try oJSON := this.JS.("(" JsonString ")")
catch {
MsgBox, Wrong JsonString!
Return
}
Return this._CreateObject(oJSON)
}
_GetJScripObject() {
VarSetCapacity(tmpFile, (MAX_PATH := 260) << !!A_IsUnicode, 0)
DllCall("GetTempFileName", Str, A_Temp, Str, "AHK", UInt, 0, Str, tmpFile)
FileAppend,
(
<component>
<public><method name='eval'/></public>
<script language='JScript'></script>
</component>
), % tmpFile
JS := ObjBindMethod( ComObjGet("script:" . tmpFile), "eval" )
FileDelete, % tmpFile
JSON._AddMethods(JS)
Return JS
}
_AddMethods(ByRef JS) {
JScript =
(
Object.prototype.GetKeys = function () {
var keys = []
for (var k in this)
if (this.hasOwnProperty(k))
keys.push(k)
return keys
}
Object.prototype.IsArray = function () {
var toStandardString = {}.toString
return toStandardString.call(this) == '[object Array]'
}
)
JS.("delete ActiveXObject; delete GetObject;")
JS.(JScript)
}
_CreateObject(ObjJS) {
res := ObjJS.IsArray()
if (res = "")
Return ObjJS
else if (res = -1) {
obj := []
Loop % ObjJS.length
obj[A_Index] := this._CreateObject(ObjJS[A_Index - 1])
}
else if (res = 0) {
obj := {}
keys := ObjJS.GetKeys()
Loop % keys.length
k := keys[A_Index - 1], obj[k] := this._CreateObject(ObjJS[k])
}
Return obj
}
}
- FanaticGuru
- Posts: 1908
- Joined: 30 Sep 2013, 22:25
Re: Need help about Associative Arrays
Full fledge JSON parsing is nice but if you just need a simple solution for a specific case then you can use a simple function like this:teadrinker wrote:Since your data is in proper JSON format, you could using any JSON parsing code to convert such string to an AHK object. One of the approaches is using JScript for this purpose.Bral wrote:I have some data is like this {"name":"Baal","age":"50"} ,this data in a Variables named DATA.
Code: Select all
DATA := "{""name"":""Baal"",""age"":""50""}"
Test := JSON_SimpleDumbConversion(DATA)
MsgBox % Test.name " age " Test.age
JSON_SimpleDumbConversion(str)
{
arr := {}
for index, element in StrSplit(RegExReplace(str, "{|}|"""), ",")
z := StrSplit(element, ":"), arr[z.1] := z.2
return arr
}
I have used cocobelgica's JSON parsing to great effect when you need the full power it brings, especially its reviver function ability.
FG
Hotkey Help - Help Dialog for Currently Running AHK Scripts
AHK Startup - Consolidate Multiply AHK Scripts with one Tray Icon
Hotstring Manager - Create and Manage Hotstrings
[Class] WinHook - Create Window Shell Hooks and Window Event Hooks
AHK Startup - Consolidate Multiply AHK Scripts with one Tray Icon
Hotstring Manager - Create and Manage Hotstrings
[Class] WinHook - Create Window Shell Hooks and Window Event Hooks
-
- Posts: 4412
- Joined: 29 Mar 2015, 09:41
- Contact:
Re: Need help about Associative Arrays
Yes, sometimes this can work.FanaticGuru wrote:if you just need a simple solution for a specific case
Re: Need help about Associative Arrays
Thanks for teadrinker and FanaticGuru, your code works fine. but cocobelgica's AutoHotkey-JSON can't work -___-
-
- Posts: 4412
- Joined: 29 Mar 2015, 09:41
- Contact:
Re: Need help about Associative Arrays
For me it works like this:Bral wrote:cocobelgica's AutoHotkey-JSON can't work
Code: Select all
DATA := "{""name"":""Baal"",""age"":""50""}"
Test := JSON.Load(DATA)
MsgBox, % Test.name . "`n" . Test.age
/**
* Lib: JSON.ahk
* JSON lib for AutoHotkey.
* Version:
* v2.1.3 [updated 04/18/2016 (MM/DD/YYYY)]
* License:
* WTFPL [http://wtfpl.net/]
* Requirements:
* Latest version of AutoHotkey (v1.1+ or v2.0-a+)
* Installation:
* Use #Include JSON.ahk or copy into a function library folder and then
* use #Include <JSON>
* Links:
* GitHub: - https://github.com/cocobelgica/AutoHotkey-JSON
* Forum Topic - http://goo.gl/r0zI8t
* Email: - cocobelgica <at> gmail <dot> com
*/
/**
* Class: JSON
* The JSON object contains methods for parsing JSON and converting values
* to JSON. Callable - NO; Instantiable - YES; Subclassable - YES;
* Nestable(via #Include) - NO.
* Methods:
* Load() - see relevant documentation before method definition header
* Dump() - see relevant documentation before method definition header
*/
class JSON
{
/**
* Method: Load
* Parses a JSON string into an AHK value
* Syntax:
* value := JSON.Load( text [, reviver ] )
* Parameter(s):
* value [retval] - parsed value
* text [in, ByRef] - JSON formatted string
* reviver [in, opt] - function object, similar to JavaScript's
* JSON.parse() 'reviver' parameter
*/
class Load extends JSON.Functor
{
Call(self, ByRef text, reviver:="")
{
this.rev := IsObject(reviver) ? reviver : false
; Object keys(and array indices) are temporarily stored in arrays so that
; we can enumerate them in the order they appear in the document/text instead
; of alphabetically. Skip if no reviver function is specified.
this.keys := this.rev ? {} : false
static quot := Chr(34), bashq := "\" . quot
, json_value := quot . "{[01234567890-tfn"
, json_value_or_array_closing := quot . "{[]01234567890-tfn"
, object_key_or_object_closing := quot . "}"
key := ""
is_key := false
root := {}
stack := [root]
next := json_value
pos := 0
while ((ch := SubStr(text, ++pos, 1)) != "") {
if InStr(" `t`r`n", ch)
continue
if !InStr(next, ch, 1)
this.ParseError(next, text, pos)
holder := stack[1]
is_array := holder.IsArray
if InStr(",:", ch) {
next := (is_key := !is_array && ch == ",") ? quot : json_value
} else if InStr("}]", ch) {
ObjRemoveAt(stack, 1)
next := stack[1]==root ? "" : stack[1].IsArray ? ",]" : ",}"
} else {
if InStr("{[", ch) {
; Check if Array() is overridden and if its return value has
; the 'IsArray' property. If so, Array() will be called normally,
; otherwise, use a custom base object for arrays
static json_array := Func("Array").IsBuiltIn || ![].IsArray ? {IsArray: true} : 0
; sacrifice readability for minor(actually negligible) performance gain
(ch == "{")
? ( is_key := true
, value := {}
, next := object_key_or_object_closing )
; ch == "["
: ( value := json_array ? new json_array : []
, next := json_value_or_array_closing )
ObjInsertAt(stack, 1, value)
if (this.keys)
this.keys[value] := []
} else {
if (ch == quot) {
i := pos
while (i := InStr(text, quot,, i+1)) {
value := StrReplace(SubStr(text, pos+1, i-pos-1), "\\", "\u005c")
static tail := A_AhkVersion<"2" ? 0 : -1
if (SubStr(value, tail) != "\")
break
}
if (!i)
this.ParseError("'", text, pos)
value := StrReplace(value, "\/", "/")
, value := StrReplace(value, bashq, quot)
, value := StrReplace(value, "\b", "`b")
, value := StrReplace(value, "\f", "`f")
, value := StrReplace(value, "\n", "`n")
, value := StrReplace(value, "\r", "`r")
, value := StrReplace(value, "\t", "`t")
pos := i ; update pos
i := 0
while (i := InStr(value, "\",, i+1)) {
if !(SubStr(value, i+1, 1) == "u")
this.ParseError("\", text, pos - StrLen(SubStr(value, i+1)))
uffff := Abs("0x" . SubStr(value, i+2, 4))
if (A_IsUnicode || uffff < 0x100)
value := SubStr(value, 1, i-1) . Chr(uffff) . SubStr(value, i+6)
}
if (is_key) {
key := value, next := ":"
continue
}
} else {
value := SubStr(text, pos, i := RegExMatch(text, "[\]\},\s]|$",, pos)-pos)
static number := "number", integer :="integer"
if value is %number%
{
if value is %integer%
value += 0
}
else if (value == "true" || value == "false")
value := %value% + 0
else if (value == "null")
value := ""
else
; we can do more here to pinpoint the actual culprit
; but that's just too much extra work.
this.ParseError(next, text, pos, i)
pos += i-1
}
next := holder==root ? "" : is_array ? ",]" : ",}"
} ; If InStr("{[", ch) { ... } else
is_array? key := ObjPush(holder, value) : holder[key] := value
if (this.keys && this.keys.HasKey(holder))
this.keys[holder].Push(key)
}
} ; while ( ... )
return this.rev ? this.Walk(root, "") : root[""]
}
ParseError(expect, ByRef text, pos, len:=1)
{
static quot := Chr(34), qurly := quot . "}"
line := StrSplit(SubStr(text, 1, pos), "`n", "`r").Length()
col := pos - InStr(text, "`n",, -(StrLen(text)-pos+1))
msg := Format("{1}`n`nLine:`t{2}`nCol:`t{3}`nChar:`t{4}"
, (expect == "") ? "Extra data"
: (expect == "'") ? "Unterminated string starting at"
: (expect == "\") ? "Invalid \escape"
: (expect == ":") ? "Expecting ':' delimiter"
: (expect == quot) ? "Expecting object key enclosed in double quotes"
: (expect == qurly) ? "Expecting object key enclosed in double quotes or object closing '}'"
: (expect == ",}") ? "Expecting ',' delimiter or object closing '}'"
: (expect == ",]") ? "Expecting ',' delimiter or array closing ']'"
: InStr(expect, "]") ? "Expecting JSON value or array closing ']'"
: "Expecting JSON value(string, number, true, false, null, object or array)"
, line, col, pos)
static offset := A_AhkVersion<"2" ? -3 : -4
throw Exception(msg, offset, SubStr(text, pos, len))
}
Walk(holder, key)
{
value := holder[key]
if IsObject(value) {
for i, k in this.keys[value] {
; check if ObjHasKey(value, k) ??
v := this.Walk(value, k)
if (v != JSON.Undefined)
value[k] := v
else
ObjDelete(value, k)
}
}
return this.rev.Call(holder, key, value)
}
}
/**
* Method: Dump
* Converts an AHK value into a JSON string
* Syntax:
* str := JSON.Dump( value [, replacer, space ] )
* Parameter(s):
* str [retval] - JSON representation of an AHK value
* value [in] - any value(object, string, number)
* replacer [in, opt] - function object, similar to JavaScript's
* JSON.stringify() 'replacer' parameter
* space [in, opt] - similar to JavaScript's JSON.stringify()
* 'space' parameter
*/
class Dump extends JSON.Functor
{
Call(self, value, replacer:="", space:="")
{
this.rep := IsObject(replacer) ? replacer : ""
this.gap := ""
if (space) {
static integer := "integer"
if space is %integer%
Loop, % ((n := Abs(space))>10 ? 10 : n)
this.gap .= " "
else
this.gap := SubStr(space, 1, 10)
this.indent := "`n"
}
return this.Str({"": value}, "")
}
Str(holder, key)
{
value := holder[key]
if (this.rep)
value := this.rep.Call(holder, key, ObjHasKey(holder, key) ? value : JSON.Undefined)
if IsObject(value) {
; Check object type, skip serialization for other object types such as
; ComObject, Func, BoundFunc, FileObject, RegExMatchObject, Property, etc.
static type := A_AhkVersion<"2" ? "" : Func("Type")
if (type ? type.Call(value) == "Object" : ObjGetCapacity(value) != "") {
if (this.gap) {
stepback := this.indent
this.indent .= this.gap
}
is_array := value.IsArray
; Array() is not overridden, rollback to old method of
; identifying array-like objects. Due to the use of a for-loop
; sparse arrays such as '[1,,3]' are detected as objects({}).
if (!is_array) {
for i in value
is_array := i == A_Index
until !is_array
}
str := ""
if (is_array) {
Loop, % value.Length() {
if (this.gap)
str .= this.indent
v := this.Str(value, A_Index)
str .= (v != "") ? v . "," : "null,"
}
} else {
colon := this.gap ? ": " : ":"
for k in value {
v := this.Str(value, k)
if (v != "") {
if (this.gap)
str .= this.indent
str .= this.Quote(k) . colon . v . ","
}
}
}
if (str != "") {
str := RTrim(str, ",")
if (this.gap)
str .= stepback
}
if (this.gap)
this.indent := stepback
return is_array ? "[" . str . "]" : "{" . str . "}"
}
} else ; is_number ? value : "value"
return ObjGetCapacity([value], 1)=="" ? value : this.Quote(value)
}
Quote(string)
{
static quot := Chr(34), bashq := "\" . quot
if (string != "") {
string := StrReplace(string, "\", "\\")
; , string := StrReplace(string, "/", "\/") ; optional in ECMAScript
, string := StrReplace(string, quot, bashq)
, string := StrReplace(string, "`b", "\b")
, string := StrReplace(string, "`f", "\f")
, string := StrReplace(string, "`n", "\n")
, string := StrReplace(string, "`r", "\r")
, string := StrReplace(string, "`t", "\t")
static rx_escapable := A_AhkVersion<"2" ? "O)[^\x20-\x7e]" : "[^\x20-\x7e]"
while RegExMatch(string, rx_escapable, m)
string := StrReplace(string, m.Value, Format("\u{1:04x}", Ord(m.Value)))
}
return quot . string . quot
}
}
/**
* Property: Undefined
* Proxy for 'undefined' type
* Syntax:
* undefined := JSON.Undefined
* Remarks:
* For use with reviver and replacer functions since AutoHotkey does not
* have an 'undefined' type. Returning blank("") or 0 won't work since these
* can't be distnguished from actual JSON values. This leaves us with objects.
* Replacer() - the caller may return a non-serializable AHK objects such as
* ComObject, Func, BoundFunc, FileObject, RegExMatchObject, and Property to
* mimic the behavior of returning 'undefined' in JavaScript but for the sake
* of code readability and convenience, it's better to do 'return JSON.Undefined'.
* Internally, the property returns a ComObject with the variant type of VT_EMPTY.
*/
Undefined[]
{
get {
static empty := {}, vt_empty := ComObject(0, &empty, 1)
return vt_empty
}
}
class Functor
{
__Call(method, ByRef arg, args*)
{
; When casting to Call(), use a new instance of the "function object"
; so as to avoid directly storing the properties(used across sub-methods)
; into the "function object" itself.
if IsObject(method)
return (new this).Call(method, arg, args*)
else if (method == "")
return (new this).Call(arg, args*)
}
}
}
Re: Need help about Associative Arrays
#Include, JSON.ahk
try
{
Http := ComObjCreate("Microsoft.XmlHttp")
Http.Open("POST", "http://www.duanrong.com/lcjh/list/0", false)
Http.Send("size=10")
JSONS := Http.ResponseText
}
FileAppend, %JSONS%, json.txt
Test := JSON.Load(JSONS)
MsgBox % Test.response.total
I get an error: "Expecting JSON value(string, number, true, false, null, object or array)".
I think this json file have data error?
try
{
Http := ComObjCreate("Microsoft.XmlHttp")
Http.Open("POST", "http://www.duanrong.com/lcjh/list/0", false)
Http.Send("size=10")
JSONS := Http.ResponseText
}
FileAppend, %JSONS%, json.txt
Test := JSON.Load(JSONS)
MsgBox % Test.response.total
I get an error: "Expecting JSON value(string, number, true, false, null, object or array)".
I think this json file have data error?
-
- Posts: 4412
- Joined: 29 Mar 2015, 09:41
- Contact:
Re: Need help about Associative Arrays
The response text is:
The error message is:{"response":{"total":55,"page":1,"exitFeeRate":0.02,"list":[{"fontColor":"#ffffff","exitRate":0.02,"status":2,"bonusRate":0.02000000,"code":"IPlan180104223321038","repayType":"IFPA","raiseOpenTime":"2018-01-04 22:33:21","vipRate":0.0,"newbieOnly":1,"id":2179,"availableQuota":828900.0,"planType":1,"quota":1000000.0,"term":1,"increaseInterest":2.0,"background":"#f7b528","name":"月月盈201800038","fixRate":0.08000000,"activityName":"新手专享1个月"},{"exitRate":0.02,"status":2,"bonusRate":0E-8,"code":"IPlan180104234237039","repayType":"IFPA","raiseOpenTime":"2018-01-04 23:42:37","vipRate":0.0,"newbieOnly":0,"id":2180,"availableQuota":494300.0,"planType":1,"quota":1000000.0,"term":3,"name":"月月盈201800039","fixRate":0.08400000},{"fontColor":"#ffffff","exitRate":0.02,"status":2,"bonusRate":0.00500000,"code":"IPlan180104192731037","repayType":"IFPA","raiseOpenTime":"2018-01-04 19:27:31","vipRate":0.0,"newbieOnly":0,"id":2178,"availableQuota":560300.0,"planType":1,"quota":1000000.0,"term":6,"increaseInterest":0.5,"background":"#f9849f","name":"月月盈201800037","fixRate":0.09000000,"activityName":"精选加息"},{"fontColor":"#ffffff","exitRate":0.02,"status":2,"bonusRate":0.00800000,"code":"IPlan180104161837036","repayType":"IFPA","raiseOpenTime":"2018-01-04 16:18:37","vipRate":0.0,"newbieOnly":0,"id":2177,"availableQuota":357100.0,"planType":1,"quota":1000000.0,"term":12,"increaseInterest":0.8,"background":"#f9849f","name":"月月盈201800036","fixRate":0.10500000,"activityName":"精选加息"},{"exitRate":0.02,"status":1,"bonusRate":0E-8,"code":"IPlan180105093250042","repayType":"IFPA","raiseOpenTime":"2018-01-05 10:00:00","vipRate":0.0,"newbieOnly":0,"id":2181,"availableQuota":500000.0,"planType":1,"quota":1000000.0,"term":1,"name":"月月盈201800040","fixRate":0.08000000}],"newbieUsable":20000.0,"totalPages":11,"size":5},"status":"SUCCESS","nowTime":1515117200265}
As I see, in that library there is an issue with parsing of numbers in such format (0E-8). However, my code works fine:Line: 1
Col: 481
Char: 481
Specifically: 0E-8
Code: Select all
JSONS =
(
{"response":{"total":55,"page":1,"exitFeeRate":0.02,"list":[{"fontColor":"#ffffff","exitRate":0.02,"status":2,"bonusRate":0.02000000,"code":"IPlan180104223321038","repayType":"IFPA","raiseOpenTime":"2018-01-04 22:33:21","vipRate":0.0,"newbieOnly":1,"id":2179,"availableQuota":828900.0,"planType":1,"quota":1000000.0,"term":1,"increaseInterest":2.0,"background":"#f7b528","name":"月月盈201800038","fixRate":0.08000000,"activityName":"新手专享1个月"},{"exitRate":0.02,"status":2,"bonusRate":0E-8,"code":"IPlan180104234237039","repayType":"IFPA","raiseOpenTime":"2018-01-04 23:42:37","vipRate":0.0,"newbieOnly":0,"id":2180,"availableQuota":494300.0,"planType":1,"quota":1000000.0,"term":3,"name":"月月盈201800039","fixRate":0.08400000},{"fontColor":"#ffffff","exitRate":0.02,"status":2,"bonusRate":0.00500000,"code":"IPlan180104192731037","repayType":"IFPA","raiseOpenTime":"2018-01-04 19:27:31","vipRate":0.0,"newbieOnly":0,"id":2178,"availableQuota":560300.0,"planType":1,"quota":1000000.0,"term":6,"increaseInterest":0.5,"background":"#f9849f","name":"月月盈201800037","fixRate":0.09000000,"activityName":"精选加息"},{"fontColor":"#ffffff","exitRate":0.02,"status":2,"bonusRate":0.00800000,"code":"IPlan180104161837036","repayType":"IFPA","raiseOpenTime":"2018-01-04 16:18:37","vipRate":0.0,"newbieOnly":0,"id":2177,"availableQuota":357100.0,"planType":1,"quota":1000000.0,"term":12,"increaseInterest":0.8,"background":"#f9849f","name":"月月盈201800036","fixRate":0.10500000,"activityName":"精选加息"},{"exitRate":0.02,"status":1,"bonusRate":0E-8,"code":"IPlan180105093250042","repayType":"IFPA","raiseOpenTime":"2018-01-05 10:00:00","vipRate":0.0,"newbieOnly":0,"id":2181,"availableQuota":500000.0,"planType":1,"quota":1000000.0,"term":1,"name":"月月盈201800040","fixRate":0.08000000}],"newbieUsable":20000.0,"totalPages":11,"size":5},"status":"SUCCESS","nowTime":1515117200265}
)
Test := JSON.Parse(JSONS)
MsgBox % Test.response.total
class JSON
{
static JS := JSON._GetJScripObject()
Parse(JsonString) {
try oJSON := this.JS.("(" JsonString ")")
catch {
MsgBox, Wrong JsonString!
Return
}
Return this._CreateObject(oJSON)
}
GetFromUrl(url, body := "") {
try {
XmlHttp := ComObjCreate("Microsoft.XmlHttp")
XmlHttp.Open("GET", url, false)
XmlHttp.Send(body)
res := XmlHttp.ResponseText
}
catch e {
MsgBox,, Microsoft.XmlHttp failed!, % "Error: " . e.message
}
if !e {
status := XmlHttp.Status
if (status != 200)
MsgBox,, Failed to load data!, % "Status code: " . status
else
Return res
}
}
_GetJScripObject() {
VarSetCapacity(tmpFile, (MAX_PATH := 260) << !!A_IsUnicode, 0)
DllCall("GetTempFileName", Str, A_Temp, Str, "AHK", UInt, 0, Str, tmpFile)
FileAppend,
(
<component>
<public><method name='eval'/></public>
<script language='JScript'></script>
</component>
), % tmpFile
JS := ObjBindMethod( ComObjGet("script:" . tmpFile), "eval" )
FileDelete, % tmpFile
JSON._AddMethods(JS)
Return JS
}
_AddMethods(ByRef JS) {
JScript =
(
Object.prototype.GetKeys = function () {
var keys = []
for (var k in this)
if (this.hasOwnProperty(k))
keys.push(k)
return keys
}
Object.prototype.IsArray = function () {
var toStandardString = {}.toString
return toStandardString.call(this) == '[object Array]'
}
)
JS.("delete ActiveXObject; delete GetObject;")
JS.(JScript)
}
_CreateObject(ObjJS) {
res := ObjJS.IsArray()
if (res = "")
Return ObjJS
else if (res = -1) {
obj := []
Loop % ObjJS.length
obj[A_Index] := this._CreateObject(ObjJS[A_Index - 1])
}
else if (res = 0) {
obj := {}
keys := ObjJS.GetKeys()
Loop % keys.length
k := keys[A_Index - 1], obj[k] := this._CreateObject(ObjJS[k])
}
Return obj
}
}
Re: Need help about Associative Arrays
Thanks for teadrinker, your code work fine.