File text array to actual array? Topic is solved

Get help with using AutoHotkey and its commands and hotkeys
User avatar
jkmgme
Posts: 3
Joined: 07 Jul 2019, 21:30

File text array to actual array?

15 Jul 2019, 18:32

Is it at all possible to make an array from an array structure in a text file?

example.txt includes:

Code: Select all

[{"container":{"spec1":"this is spec 1", "spec2":"this is spec2"}}]

Code: Select all

FileRead, exampleFile, ../example.txt
MsgBox % exampleFile
Is there any way I can use exampleFile variable as an array via conversion or some of the sort??
aifritz
Posts: 250
Joined: 29 Jul 2018, 11:30
Location: Germany

Re: File text array to actual array?

16 Jul 2019, 07:06

Interesting question, but seems to be not so easy in a few lines...
I've found this old threadhttps://autohotkey.com/board/topic/104854-string-object-file-data-structures-in-yaml-like-style/

May be there is a more actual one :?
gregster
Posts: 5129
Joined: 30 Sep 2013, 06:48

Re: File text array to actual array?

16 Jul 2019, 07:36

Since this looks like a JSON-formatted string, I would use Coco's Jxon_Load() function: https://www.autohotkey.com/boards/viewtopic.php?t=627 or use his JSON class (see same post). Here is the Jxon_Load() version:

Code: Select all

Fileread, var, example.txt
msgbox % var						; var contains a string
obj := Jxon_load(var)				; Jxon_Load loads the string into an AHK object
msgbox % obj[1].container.spec1 " , but " obj[1].container.spec2	

; Coco's Jxon_Load function: https://github.com/cocobelgica/AutoHotkey-JSON/blob/master/Jxon.ahk
Jxon_Load(ByRef src, args*)
{
	static q := Chr(34)

	key := "", is_key := false
	stack := [ tree := [] ]
	is_arr := { (tree): 1 }
	next := q . "{[01234567890-tfn"
	pos := 0
	while ( (ch := SubStr(src, ++pos, 1)) != "" )
	{
		if InStr(" `t`n`r", ch)
			continue
		if !InStr(next, ch, true)
		{
			ln := ObjLength(StrSplit(SubStr(src, 1, pos), "`n"))
			col := pos - InStr(src, "`n",, -(StrLen(src)-pos+1))

			msg := Format("{}: line {} col {} (char {})"
			,   (next == "")      ? ["Extra data", ch := SubStr(src, pos)][1]
			  : (next == "'")     ? "Unterminated string starting at"
			  : (next == "\")     ? "Invalid \escape"
			  : (next == ":")     ? "Expecting ':' delimiter"
			  : (next == q)       ? "Expecting object key enclosed in double quotes"
			  : (next == q . "}") ? "Expecting object key enclosed in double quotes or object closing '}'"
			  : (next == ",}")    ? "Expecting ',' delimiter or object closing '}'"
			  : (next == ",]")    ? "Expecting ',' delimiter or array closing ']'"
			  : [ "Expecting JSON value(string, number, [true, false, null], object or array)"
			    , ch := SubStr(src, pos, (SubStr(src, pos)~="[\]\},\s]|$")-1) ][1]
			, ln, col, pos)

			throw Exception(msg, -1, ch)
		}

		is_array := is_arr[obj := stack[1]]

		if i := InStr("{[", ch)
		{
			val := (proto := args[i]) ? new proto : {}
			is_array? ObjPush(obj, val) : obj[key] := val
			ObjInsertAt(stack, 1, val)
			
			is_arr[val] := !(is_key := ch == "{")
			next := q . (is_key ? "}" : "{[]0123456789-tfn")
		}

		else if InStr("}]", ch)
		{
			ObjRemoveAt(stack, 1)
			next := stack[1]==tree ? "" : is_arr[stack[1]] ? ",]" : ",}"
		}

		else if InStr(",:", ch)
		{
			is_key := (!is_array && ch == ",")
			next := is_key ? q : q . "{[0123456789-tfn"
		}

		else ; string | number | true | false | null
		{
			if (ch == q) ; string
			{
				i := pos
				while i := InStr(src, q,, i+1)
				{
					val := StrReplace(SubStr(src, pos+1, i-pos-1), "\\", "\u005C")
					static end := A_AhkVersion<"2" ? 0 : -1
					if (SubStr(val, end) != "\")
						break
				}
				if !i ? (pos--, next := "'") : 0
					continue

				pos := i ; update pos

				  val := StrReplace(val,    "\/",  "/")
				, val := StrReplace(val, "\" . q,    q)
				, val := StrReplace(val,    "\b", "`b")
				, val := StrReplace(val,    "\f", "`f")
				, val := StrReplace(val,    "\n", "`n")
				, val := StrReplace(val,    "\r", "`r")
				, val := StrReplace(val,    "\t", "`t")

				i := 0
				while i := InStr(val, "\",, i+1)
				{
					if (SubStr(val, i+1, 1) != "u") ? (pos -= StrLen(SubStr(val, i)), next := "\") : 0
						continue 2

					; \uXXXX - JSON unicode escape sequence
					xxxx := Abs("0x" . SubStr(val, i+2, 4))
					if (A_IsUnicode || xxxx < 0x100)
						val := SubStr(val, 1, i-1) . Chr(xxxx) . SubStr(val, i+6)
				}

				if is_key
				{
					key := val, next := ":"
					continue
				}
			}

			else ; number | true | false | null
			{
				val := SubStr(src, pos, i := RegExMatch(src, "[\]\},\s]|$",, pos)-pos)
			
			; For numerical values, numerify integers and keep floats as is.
			; I'm not yet sure if I should numerify floats in v2.0-a ...
				static number := "number", integer := "integer"
				if val is %number%
				{
					if val is %integer%
						val += 0
				}
			; in v1.1, true,false,A_PtrSize,A_IsUnicode,A_Index,A_EventInfo,
			; SOMETIMES return strings due to certain optimizations. Since it
			; is just 'SOMETIMES', numerify to be consistent w/ v2.0-a
				else if (val == "true" || val == "false")
					val := %value% + 0
			; AHK_H has built-in null, can't do 'val := %value%' where value == "null"
			; as it would raise an exception in AHK_H(overriding built-in var)
				else if (val == "null")
					val := ""
			; any other values are invalid, continue to trigger error
				else if (pos--, next := "#")
					continue
				
				pos += i-1
			}
			
			is_array? ObjPush(obj, val) : obj[key] := val
			next := obj==tree ? "" : is_array ? ",]" : ",}"
		}
	}

	return tree[1]
}
Sure, a lot of code, but usually this is not a one-time operation ;) . To reverse this (AHK object to JSON string) there is also the Jxon_Dump() function (or the class equivalent).

But yeah, there are also similar implementations on the forum, like aifritz pointed out. You could also make use of javascript, like teadrinker demonstrated and discussed here with others: https://www.autohotkey.com/boards/viewtopic.php?f=76&t=65631
teadrinker
Posts: 1856
Joined: 29 Mar 2015, 09:41
Contact:

Re: File text array to actual array?

16 Jul 2019, 08:17

Another approach:

Code: Select all

JSON = [{"container":{"spec1":"this is spec 1", "spec2":"this is spec2"}}]
arr := JsonToAhkObj(JSON)
MsgBox, % arr[1].container.spec2

JsonToAhkObj(json, flag := "") {
   static doc, JS := JsonToAhkObj("")
   if (json = "") {
      doc := ComObjCreate("htmlfile")
      doc.write("<meta http-equiv=""X-UA-Compatible"" content=""IE=9"">")
      JS := doc.parentWindow
      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.eval.(JScript)
      Return JS
   }
   else if !flag {
      try jsObj := JS.eval("(" json ")")
      catch {
         MsgBox, Wrong JSON string:`n`n%json%
         Return
      }
      Return JsonToAhkObj(jsObj, true)
   }
   else {
      res := json.IsArray()
      if (res = "")
         Return json
      else if (res = -1) {
         obj := []
         Loop % json.length
            obj[A_Index] := JsonToAhkObj(json[A_Index - 1], true)
      }
      else if (res = 0) {
         obj := {}
         keys := json.GetKeys()
         Loop % keys.length
            k := keys[A_Index - 1], obj[k] := JsonToAhkObj(json[k], true)
      }
      Return obj
   }
}
User avatar
rommmcek
Posts: 1096
Joined: 15 Aug 2014, 15:18

Re: File text array to actual array?

04 Sep 2020, 11:35

@teadrinker: Isn't there a bug/typo/pasteEror? For me doesn't work for "flat" (non associative) arrays. Don't know Java, but I guess the condition should check for Object not for String... Could you take a look please!
Spoiler
teadrinker
Posts: 1856
Joined: 29 Mar 2015, 09:41
Contact:

Re: File text array to actual array?

04 Sep 2020, 11:59

rommmcek wrote: Isn't there a bug/typo/pasteEror?
Can you provide a more simple example to demonstrate an error?
Anyway, the current version of JsonToAhk() is

Code: Select all

JsonToAHK(json, rec := false) {
   static doc := ComObjCreate("htmlfile")
         , __ := doc.write("<meta http-equiv=""X-UA-Compatible"" content=""IE=9"">")
         , JS := doc.parentWindow
   if !rec
      obj := %A_ThisFunc%(JS.eval("(" . json . ")"), true)
   else if !IsObject(json)
      obj := json
   else if JS.Object.prototype.toString.call(json) == "[object Array]" {
      obj := []
      Loop % json.length
         obj.Push( %A_ThisFunc%(json[A_Index - 1], true) )
   }
   else {
      obj := {}
      keys := JS.Object.keys(json)
      Loop % keys.length {
         k := keys[A_Index - 1]
         obj[k] := %A_ThisFunc%(json[k], true)
      }
   }
   Return obj
}
User avatar
rommmcek
Posts: 1096
Joined: 15 Aug 2014, 15:18

Re: File text array to actual array?  Topic is solved

04 Sep 2020, 12:26

Now you have new function. Doesn't work neither, except does not throw an error.

Code: Select all

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

JSON = [{"container":{"spec1":"this is spec 1", "spec2":"this is spec2"}}]
arr := JsonToAhkObj(JSON)
MsgBox, % arr[1].container.spec2

json= [[["schlank os gut","slim os good",null,null,3,null,null,[[],[]],[[["1814a2c300f02f227bcb04312cd2671a","tea_pt_en_2019q4.md"]],[["4d5e201a34474a12730540dc3bfae9fd","tea_en_de_2020q1.md"]]]]],null,"pt",null,null,[["slim os good",null,[["schlank os gut",0,true,false]],[[0,12]],"slim os good",0,0]],0.6054487,[],[["pt"],null,[0.6054487],["pt"]]]
arr := JsonToAhkObj(JSON)
MsgBox, % arr.1.1.1

JsonToAhkObj(json, flag := "") {
   static doc, JS := JsonToAhkObj("")
   if (json = "") {
      doc := ComObjCreate("htmlfile")
      doc.write("<meta http-equiv=""X-UA-Compatible"" content=""IE=9"">")
      JS := doc.parentWindow
      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.eval.(JScript)
      Return JS
   }
   else if !flag {
      try jsObj := JS.eval("(" json ")")
      catch {
         MsgBox, Wrong JSON string:`n`n%json%
         Return
      }
      Return JsonToAhkObj(jsObj, true)
   }
   else {
      res := json.IsArray()
      if (res = "")
         Return json
      else if (res = -1) {
         obj := []
         Loop % json.length
            obj[A_Index] := JsonToAhkObj(json[A_Index - 1], true)
      }
      else if (res = 0) {
         obj := {}
         keys := json.GetKeys()
         Loop % keys.length
            k := keys[A_Index - 1], obj[k] := JsonToAhkObj(json[k], true)
      }
      Return obj
   }
}
[Edit]: Sorry the new function works!

Code: Select all

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

JSON = [{"container":{"spec1":"this is spec 1", "spec2":"this is spec2"}}]
arr := JsonToAhk(JSON)
MsgBox, % arr[1].container.spec2

json= [[["schlank os gut","slim os good",null,null,3,null,null,[[],[]],[[["1814a2c300f02f227bcb04312cd2671a","tea_pt_en_2019q4.md"]],[["4d5e201a34474a12730540dc3bfae9fd","tea_en_de_2020q1.md"]]]]],null,"pt",null,null,[["slim os good",null,[["schlank os gut",0,true,false]],[[0,12]],"slim os good",0,0]],0.6054487,[],[["pt"],null,[0.6054487],["pt"]]]
arr := JsonToAhk(JSON)
MsgBox, % arr.1.1.1

JsonToAHK(json, rec := false) {
   static doc := ComObjCreate("htmlfile")
         , __ := doc.write("<meta http-equiv=""X-UA-Compatible"" content=""IE=9"">")
         , JS := doc.parentWindow
   if !rec
      obj := %A_ThisFunc%(JS.eval("(" . json . ")"), true)
   else if !IsObject(json)
      obj := json
   else if JS.Object.prototype.toString.call(json) == "[object Array]" {
      obj := []
      Loop % json.length
         obj.Push( %A_ThisFunc%(json[A_Index - 1], true) )
   }
   else {
      obj := {}
      keys := JS.Object.keys(json)
      Loop % keys.length {
         k := keys[A_Index - 1]
         obj[k] := %A_ThisFunc%(json[k], true)
      }
   }
   Return obj
}
Thanks!

Return to “Ask For Help”

Who is online

Users browsing this forum: Bing [Bot], haichen, hasantr, jmasiak, Rohwedder, RubbeH and 34 guests