1 (изменено: serzh82saratov, 2017-11-16 10:40:36)

Тема: AHK: Сохранение массива в строку

Если требуется сохранить массив, например по завершении работы сохранить в ключ ини файла или текстовый файл, а при старте скрипта восстановить массив, то используя приведённые функции можно перевести массив в строку и обратно.
Оригинал здесь, я посчитал удобным адаптировать его для использования с Base64.

ObjToBase64 - передаём массив, получаем строку.
ObjFromBase64 - передаём строку, получаем массив.

Также есть пример сравнения массивов.

----------------------------------------------

Тема для обсуждения.

----------------------------------------------

Функции: (правка: 10:37 16.11.2017)


ObjToBase64(obj) {
	If !IsObject(obj)
		Return
	VarSetCapacity(Bin, Size := RawObjectSize(obj, 0) + 8, 0)
	RawObject(obj, NumPut(Size - 8, 0 + (addr := &Bin), "Int64"), 0)
	DllCall("Crypt32.dll\CryptBinaryToString"
		, Ptr, addr, UInt, Size, UInt, 0x00000001|0x40000000, UInt, 0, UIntP, TChars, "CDECL Int")
	VarSetCapacity(Base64, Req := TChars * (A_IsUnicode ? 2 : 1 ))
	DllCall("Crypt32.dll\CryptBinaryToString"
		, Ptr, addr, UInt, Size, UInt, 0x00000001|0x40000000, Str, Base64, UIntP, Req, "CDECL Int")
	Return Base64
}

ObjFromBase64(Base64) {
	DllCall("Crypt32.dll\CryptStringToBinary", Ptr, &Base64
		, UInt, StrLen(Base64), UInt, 1, UInt, 0, UIntP, Bytes, Int, 0, Int, 0, "CDECL Int")
	VarSetCapacity(OutData, Req := Bytes * (A_IsUnicode ? 2 : 1))
	DllCall("Crypt32.dll\CryptStringToBinary", Ptr, &Base64
		, UInt, StrLen(Base64), UInt, 1, Str, OutData, UIntP, Req, Int, 0, Int, 0, "CDECL Int")
	Return ObjLoad(&OutData)
}

RawObject(obj, addr, buf := 0, objects := 0) {
	; Type.Enum:    Char.1 UChar.2 Short.3 UShort.4 Int.5 UInt.6 Int64.7 UInt64.8 Double.9 String.10 Object.11
	; Negative for keys and positive for values
	If !objects
		objects:={(""):0,(obj):0}
	Else
		objects[obj]:=(++objects[""])
	for k, v in obj
	{ ; 9 = Int64 for size and Char for type
		If IsObject(k) {
			If objects.HasKey(k)
				NumPut(-12,addr+0,"Char"),NumPut(objects[k],addr+1,"Int64"),addr+=9
			Else
				NumPut(-11,addr+0,"Char"),NumPut(sz:=RawObjectSize(k,buf),addr+1,"Int64"),RawObject(k,addr+9,buf,objects),addr+=sz+9
		} Else
			NumPut(-10,addr+0,"Char"),NumPut(sz:=StrPut(k,addr+9)*2,addr+1,"Int64"),addr+=sz+9
		If IsObject(v) {
			If objects.HasKey(v)
				NumPut(12,addr+0,"Char"),NumPut(objects[v],addr+1,"Int64"),addr+=9
			Else
				NumPut(11,addr+0,"Char"),NumPut(sz:=RawObjectSize(v,buf),addr+1,"Int64"),RawObject(v,addr+9,buf,objects),addr+=sz+9
		} Else
			NumPut(10,addr+0,"Char"),NumPut(sz:=buf?obj.GetCapacity(k):StrPut(v)*2,addr+1,"Int64"),DllCall("RtlMoveMemory","PTR",addr+9,"PTR",buf?obj.GetAddress(k):&v,"PTR",sz),addr+=sz+9
	}
}

RawObjectSize(obj,buf:=0,objects:=0){
	If !objects
		objects:={(obj):1}
	Else If !objects.HasKey(obj)
		objects[obj]:=1
	for k, v in obj
	{
		If IsObject(k)
			sz+=objects.HasKey(k)?9:RawObjectSize(k,buf,objects)+9
		Else
			sz+=StrPut(k)*2+9
		If IsObject(v)
			sz+=objects.HasKey(v)?9:RawObjectSize(v,buf,objects)+9
		Else
			sz+=(buf?obj.GetCapacity(k):StrPut(v)*2)+9
	}
	Return sz
}

ObjLoad(addr, objects := 0) {
	obj:=[],end:=addr+8+(sz:=NumGet(addr+0,"Int64")),addr+=8
	If !objects
		objects:={0:obj}
	Else
		objects.Push(obj)
	While addr < end { ; 9 = Int64 for size and Char for type
		If NumGet(addr+0,"Char")=-12
			k:=objects[NumGet(addr+1,"Int64")],addr+=9
		Else If NumGet(addr+0,"Char")=-11
			k:=ObjLoad(addr+1,objects),addr+=9+NumGet(addr+1,"Int64")
		Else If NumGet(addr+0,"Char")=-10
			sz:=NumGet(addr+1,"Int64"),k:=StrGet(addr+9),addr+=sz+9
		Else
			k:=NumGet(addr+1,SubStr("Char  UChar Short UShortInt   UInt  Int64 UInt64Double",(sz:=-NumGet(addr+0,"Char"))*6-5,6)),addr+=SubStr("112244888",sz,1)+1
		If NumGet(addr+0,"Char")= 12
			obj[k]:=objects[NumGet(addr+1,"Int64")],addr+=9
		Else If NumGet(addr+0,"Char")= 11
			obj[k]:=ObjLoad(addr+1,objects),addr+=9+NumGet(addr+1,"Int64")
		Else If NumGet(addr+0,"Char")= 10 {
			If (k + 0 != "") && !(k ~="S)\s") && (abs(k) <= 2147483647)
				obj[k]:=StrGet(addr+9),obj.SetCapacity(k,sz:=NumGet(addr+1,"Int64")),DllCall("RtlMoveMemory","PTR",obj.GetAddress(k),"PTR",addr+9,"PTR",sz),addr+=sz+9
			Else
				obj["" k]:=StrGet(addr+9),obj.SetCapacity("" k,sz:=NumGet(addr+1,"Int64")),DllCall("RtlMoveMemory","PTR",obj.GetAddress("" k),"PTR",addr+9,"PTR",sz),addr+=sz+9
		} Else
			obj[k]:=NumGet(addr+1,SubStr("Char  UChar Short UShortInt   UInt  Int64 UInt64Double",(sz:=NumGet(addr+0,"Char"))*6-5,6)),addr+=SubStr("112244888",sz,1)+1
	}
	Return obj
}
+ Пример:

#SingleInstance Force
#NoEnv

Arr := {"1key":{2key:[,,"value"]}}
Base64 := ObjToBase64(Arr)
MsgBox % Base64

Obj := ObjFromBase64(Base64)
MsgBox % Obj.1key.2key[3]

Prefix := {"LAlt":"<!","LCtrl":"<^","LShift":"<+","LWin":"<#"}
Base64 := ObjToBase64(Prefix)
MsgBox % Base64

Obj := ObjFromBase64(Base64)
for k, v in Obj
	MsgBox % k " : " v

B := ["Ivan", 345, "London"]
Base64 := ObjToBase64(B)
MsgBox % Base64

Obj := ObjFromBase64(Base64)
for k, v in Obj
	MsgBox % k " : " v
+ Пример, сохраняем экземпляр класса, загружаем. Конечно в каждой реализации своего класса могут быть свои нюансы:

#SingleInstance Force
#NoEnv

MyClass := new Class

Loop 9
{
	MyClass["v" A_Index] := A_Sec " . " A_Msec
	Sleep 10
}
MyClass.a := {b:{c:"вложенный массив"}}

Base64 := ObjToBase64(MyClass)
MsgBox % Base64

NewObj := new Class
NewObj.Load(ObjFromBase64(Base64))

for k, v in NewObj, list := ""
	list .= k " : " (IsObject(v) ? "IsObject" : v) "`n" 
MsgBox % list

NewObj.Test()
Return

class Class {
	x := 10, y := 20
	Load(Obj) { 
		for k, v in Obj
			This[k] := v
	}
	Test() {
		MsgBox % this.a.b.c
	}
} 
+ Пример выше, отдельно, загрузка экземпляра из сохранённой строки:

#SingleInstance Force
#NoEnv

Base64 = /AEAAAAAAAD2BAAAAAAAAABhAAAAC04AAAAAAAAA9gQAAAAAAAAAYgAAAAs4AAAAAAAAAPYEAAAAAAAAAGMAAAAKIgAAAAAAAAAyBDsEPgQ2BDUEPQQ9BEsEOQQgADwEMARBBEEEOAQyBAAA9gYAAAAAAAAAdgAxAAAAChIAAAAAAAAAMAA3ACAALgAgADMAOAAwAAAA9gYAAAAAAAAAdgAyAAAAChIAAAAAAAAAMAA3ACAALgAgADMAOQA1AAAA9gYAAAAAAAAAdgAzAAAAChIAAAAAAAAAMAA3ACAALgAgADQAMAA1AAAA9gYAAAAAAAAAdgA0AAAAChIAAAAAAAAAMAA3ACAALgAgADQAMgA1AAAA9gYAAAAAAAAAdgA1AAAAChIAAAAAAAAAMAA3ACAALgAgADQANAA1AAAA9gYAAAAAAAAAdgA2AAAAChIAAAAAAAAAMAA3ACAALgAgADQANQA0AAAA9gYAAAAAAAAAdgA3AAAAChIAAAAAAAAAMAA3ACAALgAgADQANwAyAAAA9gYAAAAAAAAAdgA4AAAAChIAAAAAAAAAMAA3ACAALgAgADQAOAA0AAAA9gYAAAAAAAAAdgA5AAAAChIAAAAAAAAAMAA3ACAALgAgADUAMAA0AAAA9gQAAAAAAAAAeAAAAAIK9gQAAAAAAAAAeQAAAAIU

NewObj := new Class
NewObj.Load(ObjFromBase64(Base64))
NewObj.Test()

for k, v in NewObj, list := ""
	list .= k " : " (IsObject(v) ? "IsObject" : v) "`n" 
MsgBox % list
Return

class Class { 
	Load(Obj) { 
		for k, v in Obj
			This[k] := v
	}
	Test() {
		MsgBox % this.a.b.c
	}
} 
По вопросам возмездной помощи пишите письма
E-Mail: serzh82saratov@mail.ru
OS: Win7x64, AutoHotkey_L v1.1.26.01 (Unicode 32-bit).