AutoHotkey Community

It is currently May 26th, 2012, 12:14 pm

All times are UTC [ DST ]




Post new topic Reply to topic  [ 27 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: JSON read/write parser
PostPosted: August 11th, 2008, 3:15 pm 
Offline
User avatar

Joined: August 11th, 2004, 1:47 am
Posts: 5347
Location: UK
I wrote this to help with automated hacking of my xulrunner/prism code. Others may also find it useful as a faster and more compact alternative to XML or INI.

Code:
; JSON string:
j = {"version":"1","window":{"state":3,"screenX":25,"screenY":25,"width":790,"height":605,"test":{"nested":"object"}},"sidebar":{"visible":false,"width":"200"}}
MsgBox, % json(j, "version") ; returns "1"
MsgBox, % json(j, "window.width", 800) ; returns 790, sets window->width to 800

r = { "a" : true, "b" : [ 1, [ 2.1, 2.2, { "sub" : false, "test" : [ null, "pass" ] } ], 3 ] }
MsgBox, % json(r, "b[1][2].test[1]") ; array support


Download

_________________
GitHubScriptsIronAHK Contact by email not private message.


Last edited by polyethene on September 18th, 2009, 5:03 am, edited 5 times in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: August 11th, 2008, 4:51 pm 
Offline

Joined: March 11th, 2008, 11:36 pm
Posts: 291
it reminds me Python's dictionary data type too. good for handling large variables.
i think it would be comfortable if we can skip first parameter and it creates a global variable automatically.
which would look like below
Code:
json("Screen.Width", A_ScreenWidth) ;set
MsgBox % ("Screen.Width") ;get

Thanks for sharing

_________________
Easy WinAPI - Dive into Windows API World
Benchmark your AutoHotkey skills at PlayAHK.com


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: August 11th, 2008, 5:38 pm 
Impressive! 8)


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: August 12th, 2008, 12:10 pm 
Offline
User avatar

Joined: August 11th, 2004, 1:47 am
Posts: 5347
Location: UK
heresy wrote:
i think it would be comfortable if we can skip first parameter and it creates a global variable automatically
Good idea, you can use static variable too. The main version will stay the same so you can modify external objects.

_________________
GitHubScriptsIronAHK Contact by email not private message.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: September 10th, 2008, 5:33 pm 
Offline

Joined: February 5th, 2007, 12:19 pm
Posts: 192
Location: Osnabrück, Germany
There is a problem with spaces after the :.
Would be nice if you (or someone else) could include this.
I tried to figure the problem and I think if there is Whitespace after : z is too small. But the RegexMatch with backreferences ist to complicated for me. :D

edit: Forgot to say: there's only a problem when changing values like ..."width": 790,...

Thanks for this nice piece of code.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: September 10th, 2008, 9:50 pm 
Offline

Joined: January 12th, 2008, 7:45 pm
Posts: 131
it seems to be a kickass function imho, think I'll use it


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: September 11th, 2008, 1:45 am 
Offline

Joined: February 5th, 2007, 12:19 pm
Posts: 192
Location: Osnabrück, Germany
I changed the function a little bit. Now it works with structured json files and with spaces after the :.
Code:
json(ByRef js, s, v = "") {
   j = %js%
   Loop, Parse, s, .
   {
      p = 2
      RegExMatch(A_LoopField, "([+\-]?)([^[]+)(?:\[(\d+)\])?", q), q3 := q3 ? q3 : 0
      Loop {
         If (!p := RegExMatch(j, "(""|')([^\1]+?)\1\s*:\s*((""|')?[^\4]*?\4|(\{(?:[^{}]*+|(?5))*\})|[+\-]?\d+(?:\.\d*)?|true|false|null?)\s*(?:,|$|\})", x, p))
            Return
         Else If (-1 == q3 -= x2 == q2 or q2 == "*") {
            j = %x3%
            z += p + StrLen(x2) - 2
            Break
         }
         Else p += StrLen(x)
      }
   }

  z-=StrLen(x)
  If (v !="" ) {
    NewStr := RegExReplace(x, x3 , v)
    js := RegExReplace(js, x , NewStr,"",1,z)
  }


   Return, x3 == "false" ? 0 : x3 == "true" ? 1 : x3 == "null" or x3 == "nul" ? "" : SubStr(x3, 1, 1) == "" ? SubStr(x3, 2, -1) : x3
}


Example:
Code:
j=
(
{
   "intl": {
      "app_locale": "de"
   },
   "options_window": {
      "last_tab_index": "2"

   }
}
)


test="1212"
MsgBox, % json(j,"options_window.last_tab_index", test)
MsgBox, % json(j,"options_window.last_tab_index")


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: September 11th, 2008, 11:35 am 
Offline
User avatar

Joined: August 11th, 2004, 1:47 am
Posts: 5347
Location: UK
haichen wrote:
I changed the function a little bit. Now it works with structured json files and with spaces after the :.
Thanks for writing a fix. This function is not standards compliant with array handling, the wildcard selector is also a custom extension. I had planned to release a fully conformant update but left AutoHotkey to use C# in my toolchain for which I wrote SimpleJSON. I'll look at the ahk code again tonight and will try to make the final adjustments.

_________________
GitHubScriptsIronAHK Contact by email not private message.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: September 11th, 2008, 10:46 pm 
Offline
User avatar

Joined: August 11th, 2004, 1:47 am
Posts: 5347
Location: UK
For those who are interested version 2a is what I currently use. It includes a few bug fixes and supports complex nested arrays:

Code:
j = { "a" : true, "b" : [ 1, [ 2.1, 2.2, { "sub" : false, "test" : [ null, "pass" ] } ], 3 ] }
MsgBox, % json(j, "b[1][2].test[1]")


The only problem is an odd quirk in pcre which causes a failure to match {"v":"1"} where "1" could be any one or two digit number, with or without quotes. I think this is due to conflicting atomic alternations; if anyone can write better regex please post them.

_________________
GitHubScriptsIronAHK Contact by email not private message.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: September 11th, 2008, 11:04 pm 
Offline

Joined: April 17th, 2005, 7:47 pm
Posts: 289
Location: Sauerland
Unfortunately the example in your first post doesn't work any more.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: September 11th, 2008, 11:55 pm 
Offline
User avatar

Joined: August 11th, 2004, 1:47 am
Posts: 5347
Location: UK
Rabiator wrote:
Unfortunately the example in your first post doesn't work any more.
Yes, v2 has a bug I previously mentioned - notice "version":"1" in the example and "last_tab_index": ""1212"" haichens code.

_________________
GitHubScriptsIronAHK Contact by email not private message.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: December 21st, 2008, 11:33 am 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7502
Location: Australia
Titan wrote:
The only problem is an odd quirk in pcre which causes a failure to match {"v":"1"} where "1" could be any one or two digit number, with or without quotes.
Has this been fixed? I see no such problem, but it does fail to match any quoted string containing the character 1. What is the purpose of the 1 in the highlighted character classes below?
Code:
         If (!p := RegExMatch(j, "(?<!\\)(""|')([^\-1]+?)(?<!\\)(?-1)\s*:\s*((\{(?:[^{}]++|(?-1))*\})|(\[(?:[^[\]]++|(?-1))*\])|"
            . "(?<!\\)(""|')[^\-1]*?(?<!\\)(?-1)|[+\-]?\d+(?:\.\d*)?|true|false|null?)\s*(?:,|$|\})", x, p))


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: December 21st, 2008, 12:16 pm 
Offline
User avatar

Joined: August 11th, 2004, 1:47 am
Posts: 5347
Location: UK
Lexikos wrote:
it does fail to match any quoted string containing the character 1.
After some testing I came to the same conclusion, perhaps I didn't check well enough when I made my earlier claim.

Lexikos wrote:
What is the purpose of the 1 in the highlighted character classes below? ... [^\-1]
\-1 is a relative reference to a captured subpattern - see SUBPATTERNS AS SUBROUTINES in pcre(3). I replaced the relative references with absolute ones to work around the bug and the parser works! Thanks for drawing my attention to this.

Version 2 has been committed to the SVN. The old version can be downloaded for historic reasons.

_________________
GitHubScriptsIronAHK Contact by email not private message.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: December 21st, 2008, 2:06 pm 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7502
Location: Australia
Titan wrote:
\-1 is a relative reference to a captured subpattern
I believe that is incorrect.
pcre(3) wrote:
BACKREFERENCES

\n reference by number (can be ambiguous)
\gn reference by number
\g{n} reference by number
\g{-n} relative reference by number
\k<name> reference by name (Perl)
\k'name' reference by name (Perl)
\g{name} reference by name (Perl)
\k{name} reference by name (.NET)
(?P=name) reference by name (Python)

Anyway, thanks for the prompt update.

Another thing... should ' be equivalent to "?
  • "string' is valid, but doesn't seem like it should be. Using \g{-1} instead of (?-1) would invalidate it.
  • Using "string", both " are omitted from the return value.
  • Using 'string', both ' are included in the return value.
  • Using "string', both are omitted.
  • Using 'string", both are kept.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: December 21st, 2008, 3:01 pm 
Offline
User avatar

Joined: August 11th, 2004, 1:47 am
Posts: 5347
Location: UK
Lexikos wrote:
\g{-n} relative reference by number
I must have missed that when converting (?-1) to a character class.

Lexikos wrote:
should ' be equivalent to "?
No, JSON doesn't define ' as a string token, only ". This is just a quirk in my parser - (""|') isn't matched up with SubStr(j, 1, 1) == """" on line 55 for performance reasons.

_________________
GitHubScriptsIronAHK Contact by email not private message.


Report this post
Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 27 posts ]  Go to page 1, 2  Next

All times are UTC [ DST ]


Who is online

Users browsing this forum: bbwht, Morpheus, oldbrother and 62 guests


You can post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group