1

Тема: AHK: Сохранение Массива в файл

Доброго времени суток!

В этом топике: http://forum.script-coding.com/viewtopi … 418#p48418
нашел вот такой пример кода:

Array := []

Loop 1000           ; добавляем в массив 1000 элементов, которые будут
   Array[A_Index] := A_Index    ; натуральными числами от 1 до 1000
   
MsgBox, % Array.500

Подскажите пожалуйста, можно ли сохранить массив "Array" в файл?
Если да, то покажите пожалуйста пример кода?

AutoHotKey Version: 1.1.09.02
Не спеши, а то успеешь..

2

Re: AHK: Сохранение Массива в файл

Присоединюсь к вопросу, возможно ли конвертировать (то есть без парсинга) массив в base64, и обратно воссоздать его из строки.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

3

Re: AHK: Сохранение Массива в файл

Можно в JSON-строку и обратно.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

4 (изменено: serzh82saratov, 2017-02-19 17:07:20)

Re: AHK: Сохранение Массива в файл

А массив не как отрезок в памяти выглядит, нельзя его получить как бинарные данные?
Вопрос не про JSON, а про массив АНК.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

5

Re: AHK: Сохранение Массива в файл

serzh82saratov пишет:

Вопрос не про JSON, а про массив АНК.

Я про то, что самый простой способ решить эту задачу — превратить AHK-объект в JSON-строку и сохранить в файл. Потом в обратном порядке. Есть функция для парсинга туда и обратно:

JSON := new JSON
MsgBox, % str := JSON.Dump( [{key1: "value1"}, {key2: "value2"}, {key3: "value3"}] )
obj := JSON.Load(str)
for k, v in obj
   for k, v in v
      MsgBox, % k " = " v

/**
 * 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@gmail.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*)
      }
   }
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

6

Re: AHK: Сохранение Массива в файл

serzh82saratov пишет:

А массив не как отрезок в памяти выглядит, нельзя его получить как бинарные данные?
Вопрос не про JSON, а про массив АНК.

Если массив создать через ComObjArray, то там, в принципе, можно получить адрес данных в памяти и сохранить их в бинарном виде. А может, для этого и какие-то API-функции есть. Но массив АНК более сложная конструкция и там элементы не обязаны идти один за другим, а где угодно могут находиться.

7

Re: AHK: Сохранение Массива в файл

Спасибо.

AutoHotKey Version: 1.1.09.02
Не спеши, а то успеешь..

8

Re: AHK: Сохранение Массива в файл

Пример:

;=============== ======================================================
;=============== Основные блоки 
;=======================================================================
Time_Limits_ := ""
Win_List_Limits_ := ""
Time_Count_ := ""
;=======================================================================

;=============== Начальное значение для Time_Limits := [] 
;=============== В процессе работы, кол-во переменных Time_Limits_[A_Index] может менятся +/-
Time_Limits_1 := "600", Time_Limits_2 := "800"
Time_Limits_3 := "850", Time_Limits_4 := "450"
;=============== Начальное значение для Win_List_Limits := []
;=============== В процессе работы, кол-во переменных Win_List_Limits_[A_Index] может менятся +/-
Win_List_Limits_1 = 
(
Abc
Cba
SSD
)
Win_List_Limits_2 =
(
jjg
ffd
xdr
)
;=============== Начальное значение для Time_Count := []
;=============== В процессе работы, кол-во переменных Time_Count_[A_Index] может менятся +/-
Time_Count_1 := "45", Time_Count_2 := "74", Time_Count_3 := "19"
Time_Count_4 := "24", Time_Count_5 := "17"
;=================================================================

Loop
{
	If !(Time_Limits_%A_Index%) {
		loop_List .= "|`n"
		break
	}
	loop_List .= "Time_Limits_" A_Index ":" Time_Limits_%A_Index% "`n"
}

Loop
{
	If !(Win_List_Limits_%A_Index%) {
		loop_List .= "|`n"
		break
	}
	loop_List .= "Win_List_Limits_" A_Index ":" Win_List_Limits_%A_Index% "`n"
}

Loop
{
	If !(Time_Count_%A_Index%) {
		loop_List .= "|`n"
		break
	}
	loop_List .= "Time_Count_" A_Index ":" Time_Count_%A_Index% "`n"
}

MsgBox, % loop_List

;  = перед зыкрытием скрипта - записываем в файл....
;~ FileAppend, % loop_List, % File_Name

;  = После запуска
;~ FileRead, loop_List, % File_Name

Я так понимаю, что для моей задачи, массивы вовсе не нужны? Проще использовать множество пронумерованных переменных?

AutoHotKey Version: 1.1.09.02
Не спеши, а то успеешь..

9

Re: AHK: Сохранение Массива в файл

То чувство, когда ничего тут не понимаешь .

Когда вы говорите что не можете сделать, вам всего-лишь не хватает фантазии придумать какой-нибудь костыль.

10

Re: AHK: Сохранение Массива в файл

Массивы в каком-то смысле и есть пронумерованные переменные. Правда можно вместо нумеров использовать имена:

Array := {KeyA: ValueA, KeyB: ValueB, ..., KeyZ: ValueZ}

Чтобы понять, что лучше подходит, необходимо знать поставленную задачу.

11

Re: AHK: Сохранение Массива в файл

YMP пишет:

Если массив создать через ComObjArray, то там, в принципе, можно получить адрес данных в памяти и сохранить их в бинарном виде.

А создать массив из таких данных получится?

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

12

Re: AHK: Сохранение Массива в файл

serzh82saratov пишет:

А массив не как отрезок в памяти выглядит, нельзя его получить как бинарные данные?

Можно:
https://autohotkey.com/boards/viewtopic.php?p=23832

13

Re: AHK: Сохранение Массива в файл

Malcev как всегда нашёл.
Там дальше в теме, ещё через WM_COPYDATA массивы "перекидывают".

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

14 (изменено: YMP, 2017-02-20 06:17:31)

Re: AHK: Сохранение Массива в файл

serzh82saratov пишет:

А создать массив из таких данных получится?

Да, можно ведь сохранить и дескриптор массива, т.е. структуру SAFEARRAY.

15

Re: AHK: Сохранение Массива в файл

Пример, который нашёл Malcev интересный, но если использовать JSON, мы получим в файле читаемый текст.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

16

Re: AHK: Сохранение Массива в файл

YMP а пример сложный получится?

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

17

Re: AHK: Сохранение Массива в файл

Так сходу не смогу написать. Есть там свои тонкости. Как минимум, строки нужно тоже сохранять где-то, т.к., по идее, в самом массиве только указатели на них. При восстановлении для них память нужно запрашивать не абы как, а через SysAllocString и т.п. функции. Флаги ещё там какие-то, с которыми тоже надо разбираться.

18 (изменено: migomigo, 2017-02-21 21:42:42)

Re: AHK: Сохранение Массива в файл

ypppu

ypppu пишет:

Чтобы понять, что лучше подходит, необходимо знать поставленную задачу.

В скрипте 3 массива:

Time_Counts_[]/Win_Limits_[]/Time_Limits_ в 1-ну переменную: "loop_List_Fold"

Их необходимо сохранить в 1 переменную.
Далее, после перезагрузки компьютера, необходимо их считать,  из файла распределить в 3 массива на места, для дальнейшей оброботки скриптом.

Вот попытка, но что-то не так:

+ открыть спойлер

;============================  Набор данных..
;============================
;============================


Time_Limits_1 := A_YEAR "." A_MM "." A_DD
;-----------------------------------------------------------
;~ Time_Limits_1 := Time_Mem_1    ;;;;;;; --------------------- 1.1


Time_Limits_2 := "10800000"   ; ===================== [ Допустимое время работы 3 часа] ==============
;================ [ 10 800 000 = 3 час. ] / [ 7 200 000 = 2 час. ] / [ 3 600 000 = 1 час. ] / [ 1 800 000 = 30 мин. ]
;-----------------------------------------------------------
;~ Time_Limits_2 := Time_Limit_1 ;;;;;;; ---------------------- 1.2

Time_Limits_3 := "19"
;-----------------------------------------------------------
;~ Time_Limits_3 := Time_Count_1 ;;;;-------------------------- 1.3

Time_Limits_4 := "18"              ; ====================== [ Начало разрешенного времени - кратно часам   для " T_Check_Perm(T_Perm_B, T_Perm_S)  " ] ==
;-----------------------------------------------------------
;~ Time_Limits_4 := T_Perm_B  ;;;;----------------------------- 1.4

Time_Limits_5 := "22"              ; ======================= [ Конец разрешенного времени - кратно часам ] =================
;-----------------------------------------------------------
;~ Time_Limits_5 := T_Perm_S ;;;;------------------------------ 1.5

Time_Limits_6 := "188"    ;
;-----------------------------------------------------------
;~ Time_Limits_6 := Time_Limit_B ;;;;-------------------------- 1.6

Time_Limits_7 := "1754"
;-----------------------------------------------------------
;~ Time_Limits_7 := Time_Limit_H ;;;;-------------------------- 1.7

Time_Limits_8 := A_YEAR ":" A_MM ":" A_DD
;-----------------------------------------------------------
;~ Time_Limits_8 := Time_Mem_2    ;;;;;;; --------------------- 1.8

Time_Limits_9 := "10800000"   ; ===================== [ Допустимое время работы ] ==============
;================ [ 10 800 000 = 3 час. ] / [ 7 200 000 = 2 час. ] / [ 3 600 000 = 1 час. ] / [ 1 800 000 = 30 мин. ]
;~ Time_Limits_9 := Time_Limit_Mn_Fr_H ;;;;;;; ---------------- 1.9


Win_Limits_1 = 
(
В Контакте
Home - ROBLOX
ok.ru
http://worldoftanks.ru
ROBLOX
)
;----------------------------------------------------------------
;~ Win_Limits_1 := Win_Name_Limit_1 ;;;;;;;; ----------------------- 2.1

Win_Limits_2 = 
(
WoT Client
)
;-----------------------------------------------------------------
;~ Win_Limits_2 := Win_Name_Limit_2 ;;;;;---------------------------- 2.2
;

;-----------------------------------------------------------------
Time_Counts_1 := "1"
;-----------------------------------------------------------------
;~ Time_Counts_1 := Time_Count_2 := "0" ;;;;;------------------------ 3.1

;============================
;============================
;============================

Loop
{
	If !(Time_Limits_%A_Index%)
		break
	Befo_loop_List_Extract_Report .= "Time_Limits_" A_Index ":" Time_Limits_%A_Index% "`n"
}
Loop
{
	If !(Win_Limits_%A_Index%)
		break
	Befo_loop_List_Extract_Report .= "Win_Limits" A_Index ":" Win_Limits_%A_Index% "`n"
}
Loop
{
	If !(Time_Counts_%A_Index%)
		break
	Befo_loop_List_Extract_Report .= "Time_Counts_" A_Index ":" Time_Counts_%A_Index% "`n"
}



; =========================================================
; =============================== Сохраняем 3 массива Time_Counts_[]/Win_Limits_[]/Time_Limits_ в 1-ну переменную: "loop_List_Fold"

Loop
{
	If !(Time_Limits_%A_Index%) {
		break
	}
	loop_List_Fold .= "Time_Limits_" A_Index "\" Time_Limits_%A_Index%
	If (Time_Limits_%A_Index%) {
	loop_List_Fold .= "|"
	}
}
Loop
{
	If !(Win_Limits_%A_Index%) {
		break
	}
	loop_List_Fold .= "Win_Limits_" A_Index "\" Win_Limits_%A_Index%
	If (Win_Limits_%A_Index%) {
	loop_List_Fold .= "|"
	}
}
Loop
{
	If !(Time_Counts%A_Index%) {
		Time_Counts%A_Index% := "..."
		loop_List_Fold .= Time_Counts%A_Index%
		break
	}
	loop_List_Fold .= "Time_Counts" A_Index "\" Time_Counts%A_Index%
	If (Time_Counts%A_Index%) {
	loop_List_Fold .= "|"
	}
}
;==================================================================================================




; ==================================
; ================= Очищаем 3 массива
Loop
{
	If !(Time_Limits_%A_Index%)
		break
	Time_Limits_%A_Index% := ""
}
Loop
{
	If !(Win_Limits_%A_Index%)
		break
	Win_Limits_%A_Index% := ""
}
Loop
{
	If !(Time_Counts_%A_Index%)
		break
	Time_Counts_%A_Index% := ""
}
;============================================================================================




;============================================  Извлекаем 3 массива из переменной.

TLC := "", TCC := "", WLC := "", loop_List_Extract := ""
Loop, Parse, loop_List_Fold, `|
{
	Loop, Parse, A_LoopField, `\
	{
		If !A_LoopField
			continue
		if InStr(A_LoopField, "Time_Limits_")
		{
			TLC++
			Time_Limits_%TLC% := RegExReplace(A_LoopField, ".+\:(\d+)", "$1")
			loop_List_Extract .= Time_Limits_%TLC% "|"
		}

		if InStr(A_LoopField, "Win_Limits_")
		{
			WLC++
			Win_Limits_%WLC% := RegExReplace(A_LoopField, "^\w+:")
			loop_List_Extract .= Win_Limits_%WLC% "|"
		}

		if InStr(A_LoopField, "Time_Counts_")
		{
			TCC++
			Time_Counts_%TCC% := RegExReplace(A_LoopField, "^\w+:")
			loop_List_Extract .= Time_Counts_%TCC% "|"
		}
	}
}



; ==============================================   Сравниваем что получилось
Loop
{
	If !(Time_Limits_%A_Index%)
		break
	loop_List_Extract_Report .= "Time_Limits_" A_Index ":" Time_Limits_%A_Index% "`n"
}
Loop
{
	If !(Win_Limits_%A_Index%)
		break
	loop_List_Extract_Report .= "Win_Limits" A_Index ":" Win_Limits_%A_Index% "`n"
}
Loop
{
	If !(Time_Counts_%A_Index%)
		break
	loop_List_Extract_Report .= "Time_Counts_" A_Index ":" Time_Counts_%A_Index% "`n"
}



Gui, add, text, cRed, Запарсили массивы
Gui, add, text,, % Befo_loop_List_Extract_Report
Gui, add, text, cRed, Распарсили массивы
Gui, add, text,, % loop_List_Extract_Report
Gui, Show, 
return

GuiClose:
ExitApp
AutoHotKey Version: 1.1.09.02
Не спеши, а то успеешь..

19

Re: AHK: Сохранение Массива в файл

А можно простой пример? Отдельно названия массивов, отдельно содержимое массивов? Штуки три достаточно.
Длинный код не понятно что демонстрирует. Кстати нужно его оформить тегом "code".

20

Re: AHK: Сохранение Массива в файл

YMP
Если код получается также сложен, как в примере HotKeyIt, то видимо нет смысла...

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

21

Re: AHK: Сохранение Массива в файл

https://autohotkey.com/docs/objects/File.htm
RawRead
RawWrite
Seek

22 (изменено: migomigo, 2017-02-22 02:34:39)

Re: AHK: Сохранение Массива в файл

Я то думал что упростил пример..
Попробую переиначить, выхода нет, так как на кону здоровая психика ребенка!

Офтоп:
На этот форум меня привели игры. Попытка получить незначительное преимущество на соревнованиях (2009г.)..

Теперь, спустя годы, (2017г.)вернулся на этот форму работая над скриптом для засчитаны ребенка от игор..  )))

AutoHotKey Version: 1.1.09.02
Не спеши, а то успеешь..

23 (изменено: migomigo, 2017-02-22 04:00:54)

Re: AHK: Сохранение Массива в файл

Всего 3 массива.

Массив №1:
В нем данные, это цыфры, время или даты. Могут быть разделены точкой или двоеточием.

Time_Limits_[3]
	Time_Limits_1 := "1570006"
	Time_Limits_2 := "10:30"
	Time_Limits_3 := "2017.02.23"

Массив №2:
В нем данные, это ключевые слова определяющие активное приложение, страничку интернета и т.д.. Может быть что угодно, и написно с новой строчки:

Win_Counts_[2]
	Win_Counts_1 := "http://worldoftanks.ru" "`n" "Home - ROBLOX" "`n" "ok.ru"
	Win_Counts_2 := "ROBLOX" "`n" "WoT Client" "`n"

Массив №3:
В нем данные, это цыфры, без каких либо иных знаков

Time_Counts_[3]
	Time_Counts_1 := "12"
	Time_Counts_2 := "3600000"
	Time_Counts_3 := "65470"

Количество строк каждого массива может изменяться в процессе работы скрипта..
Например при запуске скрипта:

Time_Counts_[3]
Win_Counts_[2]
Win_Counts_[10]

После завершения работы скрипта, может выглядеть так:

Time_Counts_[15]
Win_Counts_[4]
Win_Counts_[8]

Задача, запарсить это все в 1 переменную для сохранения в файл.



Дальше, распарсить и обратно разсовать по своим строчкам в свои массивы, при это сохранить очередность.

AutoHotKey Version: 1.1.09.02
Не спеши, а то успеешь..

24 (изменено: migomigo, 2017-02-22 03:34:16)

Re: AHK: Сохранение Массива в файл

Как запаковать 3 массива, я примерно понимаю.

+ открыть спойлер
	Time_Limits_1 := "1570006"
	Time_Limits_2 := "10:30"
	Win_Counts_1 := "http://worldoftanks.ru" "`n" "Home - ROBLOX" "`n" "ok.ru"
	Win_Counts_2 := "ROBLOX" "`n" "WoT Client" "`n"
	Time_Counts_1 := "12"
	Time_Counts_2 := "3600000"
	
	
Loop ; Последовательно записываем в переменную "array_block .=" массив Time_Limits_[] разделяя строки "|и*"
{
	If !(Time_Limits_%A_Index%)
		break
	array_block .= "Time_Limits_" A_Index "|" Time_Limits_%A_Index% "*"
}

Loop  ; Последовательно записываем в переменную "array_block .=" массив Win_Limits_[] разделяя строки "|и*"
{
	If !(Win_Counts_%A_Index%)
		break
	array_block .= "Win_Counts_" A_Index "|" Win_Counts_%A_Index% "*"
}
Loop   ; Последовательно записываем в переменную "array_block .=" массив Time_Counts_[] разделяя строки "|и*"
{
	If !(Time_Counts_%A_Index%) {
		Time_Counts_%A_Index% := "..."
		array_block .= Time_Counts_%A_Index%
		break
	}
	array_block .= "Time_Counts_" A_Index "|" Time_Counts_%A_Index% "*"
}
	
Gui, add, text, cRed, Запарсили массивы
Gui, add, text,, % array_block
Gui, Show, 
return

GuiClose:
ExitApp

А вот правильно извлечь запакованное - не выходит..

AutoHotKey Version: 1.1.09.02
Не спеши, а то успеешь..

25

Re: AHK: Сохранение Массива в файл

Ну так FileAppend что б записать, FileRead и Loop, Parse что б считать. Берешь уникальный разделитель и вставляешь между элементами массива, потом ложишь все это на диск. Обратно – считываешь и парсишь. Если массивов много то можно через несколько файлов работать под отдельные массивы – так проще.

26 (изменено: migomigo, 2017-02-22 04:29:05)

Re: AHK: Сохранение Массива в файл

Пока что дело дальше этого не заходит.

+ открыть спойлер
Time_Limits_1 := "1570006"
	Time_Limits_2 := "10:30"
	Win_Counts_1 := "http://worldoftanks.ru" "`n" "Home - ROBLOX" "`n" "ok.ru"
	Win_Counts_2 := "ROBLOX" "`n" "WoT Client"
	Time_Counts_1 := "12"
	Time_Counts_2 := "3600000"
	
	
Loop ; Последовательно записываем в переменную "array_block .=" массив Time_Limits_[] разделяя строки "|и*"
{
	If !(Time_Limits_%A_Index%)
		break
	array_block .= "Time_Limits_" A_Index "|" Time_Limits_%A_Index% "*"
	array_block_Temp_1 .= "Time_Limits_" A_Index "|" Time_Limits_%A_Index% "*"   ; ==================== Сбор информации
}
Loop  ; Последовательно записываем в переменную "array_block .=" массив Win_Limits_[] разделяя строки "|и*"
{
	If !(Win_Counts_%A_Index%)
		break
	array_block .= "Win_Counts_" A_Index "|" Win_Counts_%A_Index% "*"
	array_block_Temp_2 .= "Win_Counts_" A_Index "|" Win_Counts_%A_Index% "*"    ; ==================== Сбор информации
}
Loop   ; Последовательно записываем в переменную "array_block .=" массив Time_Counts_[] разделяя строки "|и*"
{
	If !(Time_Counts_%A_Index%) {
		Time_Counts_%A_Index% := "..."
		array_block .= Time_Counts_%A_Index%
		break
	}
	array_block .= "Time_Counts_" A_Index "|" Time_Counts_%A_Index% "*"
	array_block_Temp_3 .= "Win_Counts_" A_Index "|" Win_Counts_%A_Index% "*"     ; ==================== Сбор информации 1
}

TL =
WC =
TC =

Loop, Parse, array_block, `*             ;============================================================= Распаковка - Этап 1
{
	If !(A_LoopField)
		continue
	Time_Limits_ .= A_LoopField "`n"
	Arrray_%A_Index% := A_LoopField
	Loop, parse, Arrray_%A_Index%, `|    ;============================================================= Распаковка - Этап 2
	{
		If !(A_LoopField)
		continue
		CCC++
		If (CCC = "2") {
			CCC := "0"
			if InStr(A_LoopField, "Time_Limits_" false)
			{
				TL++
				MsgBox, % Time_Limits_%TLC% := A_LoopField
				Report_ .= Time_Limits_ "`n" Time_Limits_%TLC% "`n"            ; ==================== Сбор информации 2
			}
			if InStr(A_LoopField, "Win_Counts_" True)
			{
				WC++
				MsgBox, % Win_Counts_%WC% := A_LoopField
				Report_ .= Win_Counts_ "`n" Win_Counts_%WC% "`n"            ; ==================== Сбор информации 2
			}
			if InStr(A_LoopField, "Time_Counts_" True)
			{
				TC++
				MsgBox, % Time_Counts_%TC% := A_LoopField
				Report_ .= Time_Counts_ "`n" Time_Counts_%TC% "`n"            ; ==================== Сбор информации 2
			}
		}			
	}
	
}


Gui, add, text, cRed, Блок №1:
Gui, add, Edit,, % array_block_Temp_1
Gui, add, text, cRed, Блок №2:
Gui, add, Edit,, % array_block_Temp_2
Gui, add, text, cRed, Блок №3:
Gui, add, Edit,, % array_block_Temp_3
Gui, add, text, cGreen, Запарсили массивы
Gui, add, Edit,, % array_block
Gui, add, text, cBlue, Распаковка - Этап 1
Gui, add, Edit,, % Time_Limits_
Gui, add, text, cBlue, Распаковка - Этап 2 (Тупик)
Gui, add, Edit,, % Report_
Gui, Show, 
return

GuiClose:
ExitApp
AutoHotKey Version: 1.1.09.02
Не спеши, а то успеешь..

27 (изменено: YMP, 2017-02-23 16:07:43)

Re: AHK: Сохранение Массива в файл

А не проще ли использовать INI-файл? Только `n на что-нибудь заменять при сохранении, а при загрузке вставлять обратно.


Time_Limits_1 := "1570006"
Time_Limits_2 := "10:30"
Win_Counts_1 := "http://worldoftanks.ru" "`n" "Home - ROBLOX" "`n" "ok.ru"
Win_Counts_2 := "ROBLOX" "`n" "WoT Client"
Time_Counts_1 := "12"
Time_Counts_2 := "3600000"

ArrayNames := ["Time_Limits", "Win_Counts", "Time_Counts"]
IniFile = %A_Temp%\SavedArray.txt
FileDelete, %IniFile%

; Сохранение
Loop, % ArrayNames._MaxIndex()
{
    SaveArray(ArrayNames[A_Index], IniFile)
}

; Загрузка
Loop, % ArrayNames._MaxIndex()
{
    LoadArray(ArrayNames[A_Index], IniFile)
}

; Проверка
Vars =
(
Time_Limits_1 = %Time_Limits_1%
Time_Limits_2 = %Time_Limits_2%
Win_Counts_1 = %Win_Counts_1%
Win_Counts_2 = %Win_Counts_2%
Time_Counts_1 = %Time_Counts_1%
Time_Counts_2 = %Time_Counts_2%
)
MsgBox, %Vars%

; ======================== Функции =====================================

SaveArray(Name, File)
{
    Loop {
        Key = %Name%_%A_Index%
        Value := %Key%
        If (Value = "") {
            Break
        }
        StringReplace, Value, Value, `n, |, A
        IniWrite, %Value%, %File%, Arrays, %Key%
    }
}

LoadArray(Name, File)
{
    Loop {
        Key = %Name%_%A_Index%
        IniRead, Value, %File%, Arrays, %Key%, %A_Space%
        If (Value = "") {
            Break
        }
        StringReplace, Value, Value, |, `n, A
        %Key% = %Value%
    }
}

28

Re: AHK: Сохранение Массива в файл

YMP
Идеально. То что надо! Спасибо. 
Не до конца понимаю механизм работы, но знаю как его применить..



Я правильно понимаю,

ArrayNames := ["Time_Limits", "Win_Counts", "Time_Counts"]

тут создается 3 массива?


MaxIndex()

А эта некая встроенная функция?

AutoHotKey Version: 1.1.09.02
Не спеши, а то успеешь..

29

Re: AHK: Сохранение Массива в файл

migomigo, а чем не устраивает IniWrite и IniRead? Какая польза от того, что все переменные сохраняются в одну строку?

30 (изменено: YMP, 2017-02-22 18:28:47)

Re: AHK: Сохранение Массива в файл

migomigo
Нет, создаётся один массив из трёх элементов, которыми являются названия ваших псевдомассивов. А _MaxIndex() — это метод массива, возвращающий максимальный задействованный в нём индекс элемента. В данном случае он равен числу элементов.

31 (изменено: migomigo, 2017-02-23 02:18:11)

Re: AHK: Сохранение Массива в файл

ypppu
Да в принципе ничем..
Сам не знаю чего я уцепился за FileAppend.

Вероятно, просто инерция..
Возможно, было желание понять как можно сделать скрипт сохранения массива в 1 файл сразу. 


IniWrite
IniRead

Полностью устраивают.

Уже всунул в скрипт пример от YMP, все замечательно работает.

Чуть позднее, как отшлифую функционал, выложу скрипт родительского контроля. Может одобрите..

AutoHotKey Version: 1.1.09.02
Не спеши, а то успеешь..

32

Re: AHK: Сохранение Массива в файл

YMP, у Вас используются команды IniWrite и IniRead. А зачем тогда усложнять ввод переменных

Win_Counts_1 := "http://worldoftanks.ru" "`n" "Home - ROBLOX" "`n" "ok.ru"

и внедрять символ конвейера в файле настроек? Вроде стандартными средствами более наглядно:

Win_Counts_1 = 
(
http://worldoftanks.ru
Home - ROBLOX
ok.ru
)

33

Re: AHK: Сохранение Массива в файл

ypppu
Переменные я просто скопировал из кода migomigo, они же чисто для примера. А замена новых строк нужна, чтобы потом из INI-файла нормально считалось.

34

Re: AHK: Сохранение Массива в файл

YMP, если в названии окна будет символ "|", то ваш код будет ошибочным.

Win_Counts_1 := "http://worldoftanks.ru" "`n" "Home | ROBLOX" "`n" "ok.ru"

35

Re: AHK: Сохранение Массива в файл

Malcev
Это только пример. Никто не запрещает использовать другой символ. Я ведь там написал: "Только `n на что-нибудь заменять при сохранении, а при загрузке вставлять обратно." На что-нибудь, а не на |.

36

Re: AHK: Сохранение Массива в файл

YMP пишет:

чтобы потом из INI-файла нормально считалось

YMP, точно, а считать такой ini-файл нормально я уже не смогу, разве что свою функцию писать.

37

Re: AHK: Сохранение Массива в файл

А можно использовать как разделитель, уникальную комбинацию символов?
Например:

№;%/\

Или что-то в этом роде?..

AutoHotKey Version: 1.1.09.02
Не спеши, а то успеешь..

38 (изменено: Malcev, 2017-02-23 16:32:46)

Re: AHK: Сохранение Массива в файл

YMP, в вашем коде обнуление переменных после сохранения не происходит, так что проверка бессмысленна.
Так, мне кажется, надежнее:

Time_Limits_1 := "1570006"
Time_Limits_2 := "10:30"
Win_Counts_1 := "http://worldoftanks.ru" "`n" "Home | ROBLOX" "`n" "ok.ru"
Win_Counts_2 := "ROBLOX" "`n" "WoT Client"
Time_Counts_1 := "12"
Time_Counts_2 := "3600000"



ArrayNames := ["Time_Limits", "Win_Counts", "Time_Counts"]
IniFile = %A_Temp%\SavedArray.txt
FileDelete, %IniFile%

; Сохранение
Loop, % ArrayNames._MaxIndex()
{
    SaveArray(ArrayNames[A_Index], IniFile)
}


; Обнуление
Time_Limits_1 = 
Time_Limits_2 = 
Win_Counts_1 = 
Win_Counts_2 = 
Time_Counts_1 = 
Time_Counts_2 = 


; Загрузка
Loop, % ArrayNames._MaxIndex()
{
    LoadArray(ArrayNames[A_Index], IniFile)
}

; Проверка
Vars =
(
Time_Limits_1 = %Time_Limits_1%
Time_Limits_2 = %Time_Limits_2%
Win_Counts_1 = %Win_Counts_1%
Win_Counts_2 = %Win_Counts_2%
Time_Counts_1 = %Time_Counts_1%
Time_Counts_2 = %Time_Counts_2%
)
MsgBox, %Vars%

; ======================== Функции =====================================

SaveArray(Name, File)
{
   Loop
   {
      Key = %Name%_%A_Index%
      Value := %Key%
      If (Value = "")
         Break
      Loop, Parse, value, `r`n
         IniWrite, %A_LoopField%, %File%, Arrays, %A_Index%|%Key%
   }
}

LoadArray(Name, File)
{
   Loop
   {
      Key = %Name%_%A_Index%
      loop
      {
         IniRead, Value, %File%, Arrays, %A_Index%|%Key%, %A_Space%
         If (Value = "")
         {
            if (Values = "")
               break 2
            %Key% = %Values%
            Values := ""
            break
         }
         If A_Index = 1
            values := value 
         else
            values .= "`n" value
      }
   }
}

39

Re: AHK: Сохранение Массива в файл

Malcev пишет:

YMP, в вашем коде обнуление переменных после сохранения не происходит, так что проверка бессмысленна.

Они перезаписываются функцией LoadArray. Да и вообще это чисто для демонстрации. Ясно же было, что migomigo проверит код в реальных условиях, т.е. запустит скрипт с уже существующим INI-файлом и посмотрит, как загрузились переменные.

40

Re: AHK: Сохранение Массива в файл

Пример на одномерный массив


B:= ["Ivan", 345, "London"]
Save("Test.txt", B)
Run, Test.txt
MsgBox, % "Continue"
C:= Load("Test.txt")
MsgBox, % "Size " C.MaxIndex() "`n" C[1] "`n" C[2] "`n" C[3] "`n"
ExitApp

Save(fName, ByRef A, dl := "|"){
	if FileExist(fName)
		FileDelete, % fName
	Loop, % A.MaxIndex()
		S.= A[A_Index] dl
	FileAppend, % Trim(S, dl), % fName
}

Load(fName, dl:= "|"){
	FileRead, S, % fName
	A:= []
	Loop, parse, S, % dl
		A[A_Index]:= A_LoopField
	return A
}

41 (изменено: YMP, 2017-02-23 16:09:48)

Re: AHK: Сохранение Массива в файл

migomigo пишет:

А можно использовать как разделитель, уникальную комбинацию символов?

Можно и комбинацию, почему бы нет. Это, строго говоря, не разделитель, а временная замена для новой строки.

Кстати, нужно заменить в обеих функциях If (!Value) на If (Value = ""), ведь в переменной, по идее, и ноль может быть, а это уже непустое значение.

42

Re: AHK: Сохранение Массива в файл

YMP пишет:

Они перезаписываются функцией LoadArray

Я этого не наблюдаю:

Time_Limits_1 := "1570006"
Time_Limits_2 := "10:30"
Win_Counts_1 := "http://worldoftanks.ru" "`n" "Home - ROBLOX" "`n" "ok.ru"
Win_Counts_2 := "ROBLOX" "`n" "WoT Client"
Time_Counts_1 := "12"
Time_Counts_2 := "3600000"

ArrayNames := ["Time_Limits", "Win_Counts", "Time_Counts"]
IniFile = %A_Temp%\SavedArray.txt
FileDelete, %IniFile%



; Загрузка
Loop, % ArrayNames._MaxIndex()
{
    LoadArray(ArrayNames[A_Index], IniFile)
}

; Проверка
Vars =
(
Time_Limits_1 = %Time_Limits_1%
Time_Limits_2 = %Time_Limits_2%
Win_Counts_1 = %Win_Counts_1%
Win_Counts_2 = %Win_Counts_2%
Time_Counts_1 = %Time_Counts_1%
Time_Counts_2 = %Time_Counts_2%
)
MsgBox, %Vars%

; ======================== Функции =====================================

SaveArray(Name, File)
{
    Loop {
        Key = %Name%_%A_Index%
        Value := %Key%
        If (!Value) {
            Break
        }
        StringReplace, Value, Value, `n, |, A
        IniWrite, %Value%, %File%, Arrays, %Key%
    }
}

LoadArray(Name, File)
{
    Loop {
        Key = %Name%_%A_Index%
        IniRead, Value, %File%, Arrays, %Key%, %A_Space%
        If (!Value) {
            Break
        }
        StringReplace, Value, Value, |, `n, A
        %Key% = %Value%
    }
}

43

Re: AHK: Сохранение Массива в файл

Malcev пишет:

Я этого не наблюдаю:

Естественно. Раз файла нет, то и загружать нечего.

44

Re: AHK: Сохранение Массива в файл

Даже если будет, но с меньшим колличеством переменных, то проверка покажет загруженность всех переменных прописанных в скрипте.
Поэтому я и написал, что проверка без обнуления переменных бессмысленна.

45

Re: AHK: Сохранение Массива в файл

Malcev
Так ведь в реальных условиях они скриптом не создаются, а берутся из INI-файла. По крайней мере, так я понял. Поэтому меньшего количества быть не может. Это потом их может стать больше или меньше.

46 (изменено: Malcev, 2017-02-23 16:23:44)

Re: AHK: Сохранение Массива в файл

Я тоже так понял.
Но также я понял, что проверку вы вставили для того, чтобы убедиться, что ini файл создан верно, все данные в него записались и все успешно загрузились.
А без обнуления перемнных, что нам эта проверка даёт?

47

Re: AHK: Сохранение Массива в файл

По крайней мере видно, что данные не портятся. А вообще, это больше рекламный ход. Сам я проверил другими средствами. С обнулением было бы правильно, но лень было его делать. В конце концов migomigo же разработчик, а не ламер какой-нибудь, всё проверит в деле.

48

Re: AHK: Сохранение Массива в файл

Для многострочных переменных сделал функцию на замену IniRead и IniWrite. Вместо разделителя строки используется тег <linefeed> (можно любой другой подставить). Предлагаю в Коллекцию. Есть какие предложения / дополнения / критика?

Win_Counts_1 =
(
http://worldoftanks.ru Home - ROBLOX
ok.ru
)

MyIniWrite(Win_Counts_1, "Filename.ini", "Section", "Key")
MyIniRead(OutputVar, "Filename.ini", "Section", "Key", "MyError")
MsgBox, % OutputVar
Return

MyIniWrite(Value, Filename, Section, Key)
{
StringReplace, Value, Value, `n, <linefeed>, All
IniWrite, %Value%, %Filename%, %Section%, %Key%
}

MyIniRead(ByRef OutputVar, Filename, Section, Key, ByRef Default)
{
IniRead,  OutputVar, %Filename%, %Section%, %Key%, %Default%
StringReplace, OutputVar, OutputVar, <linefeed>, `n, All
}

49

Re: AHK: Сохранение Массива в файл

ypppu, а почему не хотите вообще без замен обойтись, как в 38 посте?

50

Re: AHK: Сохранение Массива в файл

В моём варианте есть несколько отличий:
- пользователю не нужно предварительно подготавливать содержимое многострочных переменных;
- синтаксис функций очень похож на привычные  IniRead и IniWrite;
- я не ставил задачу сохранения массивов, просто многим интересно было бы сохранять многострочные переменные без особых костылей.

51

Re: AHK: Сохранение Массива в файл

Не вижу отличий:

Win_Counts_1 =
(
http://worldoftanks.ru Home - ROBLOX
ok.ru
)

MyIniWrite(Win_Counts_1, "Filename.ini", "Section", "Key")
MyIniRead(OutputVar, "Filename.ini", "Section", "Key", "MyError")
MsgBox, % OutputVar
Return

MyIniWrite(Value, Filename, Section, Key)
{
   Loop, Parse, value, `r`n
      IniWrite, %A_LoopField%, %Filename%, %Section%, %A_Index%|%Key%
}


MyIniRead(ByRef OutputVar, Filename, Section, Key, ByRef Default)
{
   loop
   {
      IniRead, Value, %Filename%, %Section%, %A_Index%|%Key%, %Default%
      If (Value = Default)
         break
      If A_Index = 1
         OutputVar := value 
      else
         OutputVar .= "`n" value
    }
}

52 (изменено: stealzy, 2017-02-23 21:23:30)

Re: AHK: Сохранение Массива в файл

ypppu, зачем <linefeed> выдумывать? У нас в AHK уже есть `n. А если строка содержит <linefeed>, что делать?

Win_Counts_1 =
(
http://worldoftanks.ru`n
Home - ROBLOX
ok.ru
--
)

MyIniWrite(Win_Counts_1, "Filename.ini", "Section", "Key")
value := MyIniRead("Filename.ini", "Section", "Key", "MyError")
MsgBox % value
Return

MyIniWrite(val, Filename, Section, Key) {
	StringReplace val, val, `n, ``n, All
	IniWrite %val%, %Filename%, %Section%, %Key%
}
MyIniRead(Filename, Section, Key, ByRef Default) {
	IniRead  val, %Filename%, %Section%, %Key%, %Default%
	StringReplace, val, val, ``n, `n, All
	Return val
}

Вообще дались вам эти ini функции. Я использую простую запись в файл в формате json в одном своем скрипте и ничего интересного в этом не вижу.

53

Re: AHK: Сохранение Массива в файл

Malcev пишет:

Не вижу отличий:

По сути то же самое, да.

stealzy пишет:

ypppu, зачем <linefeed> выдумывать? У нас в AHK уже есть `n. А если строка содержит <linefeed>, что делать?

А если строка содержит `n ? Я ж сразу написал, что можно любой другой разделитель подставить.
А функции полезные, люди иногда спрашивают, интересуются.

54 (изменено: stealzy, 2017-02-23 21:58:22)

Re: AHK: Сохранение Массива в файл

ypppu пишет:

А если строка содержит `n ?

Вопрос интересный с точки зрения написания парсера, потому и спрашиваю).

Win_Counts_1 =
(
http://worldoftanks.ru``n--
Home - ROBLOX
)

MyIniWrite(Win_Counts_1, "Filename.ini", "Section", "Key")
value := MyIniRead("Filename.ini", "Section", "Key", "MyError")
MsgBox % value
Return

MyIniWrite(val, Filename, Section, Key) {
	StringReplace val, val, ``, -temp-, All
	StringReplace val, val, `n, ``n, All
	StringReplace val, val, -temp-, ````, All
	IniWrite %val%, %Filename%, %Section%, %Key%
}
MyIniRead(Filename, Section, Key, ByRef Default) {
	IniRead  val, %Filename%, %Section%, %Key%, %Default%
	StringReplace, val, val, ````, -temp-, All
	StringReplace, val, val, ``n, `n, All
	StringReplace, val, val, -temp-, ````, All
	Return val
}

Можно ли обойтись без -temp-?
Нужно заменить все переносы строки на `n, а ` экранировать этим же символом.

55

Re: AHK: Сохранение Массива в файл

stealzy, все эти замены ненадёжны:

Win_Counts_1 =
(
http://worldoftanks.ru-temp-``n--
Home - ROBLOX
)

56 (изменено: stealzy, 2017-02-23 21:59:58)

Re: AHK: Сохранение Массива в файл

Malcev, я про то и спрашиваю, как без них обойтись. Пример в 55 сообщении подправлен.

57 (изменено: Malcev, 2017-02-23 22:01:23)

Re: AHK: Сохранение Массива в файл

Не работает ваш пример:

Win_Counts_1 =
(
http://worldoftanks.ru-temp-``n--
Home - ROBLOX
)
MsgBox % Win_Counts_1

MyIniWrite(Win_Counts_1, "Filename.ini", "Section", "Key")
value := MyIniRead("Filename.ini", "Section", "Key", "MyError")
MsgBox % value
Return

MyIniWrite(val, Filename, Section, Key) {
	StringReplace val, val, ``, -temp-, All
	StringReplace val, val, `n, ``n, All
	StringReplace val, val, -temp-, ````, All
	IniWrite %val%, %Filename%, %Section%, %Key%
}
MyIniRead(Filename, Section, Key, ByRef Default) {
	IniRead  val, %Filename%, %Section%, %Key%, %Default%
	StringReplace, val, val, ````, -temp-, All
	StringReplace, val, val, ``n, `n, All
	StringReplace, val, val, -temp-, ````, All
	Return val
}

Malcev, я про то и спрашиваю, как без них обойтись

52 пост.

58

Re: AHK: Сохранение Массива в файл

Malcev, вы уже дважды пишете что не работает, то что и не должно работать :@.
Вопрос то был, как без замен сделать.

59

Re: AHK: Сохранение Массива в файл

Так я и пишу, что в 52 посте сделано без замен.
Или вы мы про разные замены говорим?

60 (изменено: stealzy, 2017-02-23 22:35:04)

Re: AHK: Сохранение Массива в файл

Вроде понял: команда StringReplace val, val, `n, ``n, All заменяет без разбору, как переносы строки, так и сочетание символов `n. Т.е. после прохода такой заменой отличить одно от другого невозможно, вот в чем проблема.
А команда Loop, Parse, value, `n различает такие вещи. Malcev прав.

61

Re: AHK: Сохранение Массива в файл

+ stealzy
stealzy пишет:

Offtop: migomigo даже If Else не умеет использовать.

У вас другого способа самоутверждения кроме как пыжится собственным величием, гениального программиста  - нет?

Если вы тоже хотите стать разработчиком, добавьте скрипт, и модераторы моментально это отметят.

Даже мне, художнику-дизайнеру, с гуманитарным складом ума удалось пополнить коллекцию скриптов этого замечательного форума!
Вашему гению, с намного большими познаниями в матемматических науках, это может удастся намного лучше моего!
Как вы считаете?

Вас модератор уже спрашивал о вашей разработке.
http://forum.script-coding.com/viewtopi … 27#p112727
Это ваш шанс!

AutoHotKey Version: 1.1.09.02
Не спеши, а то успеешь..

62 (изменено: serzh82saratov, 2017-03-07 18:29:00)

Re: AHK: Сохранение Массива в файл

Уже выкладывал одну версию, теперь хочу добавить в коллекцию в таком виде.

Так как функции RawObject, RawObjectSize, ObjLoad настолько же изменил насколько их понял (то есть оставил почти в оригинале), то хочу спросить не находит ли кто ошибок, и нужно ли это в коллекции?


#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



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" (A_IsUnicode ? "W" : "A")
		, 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" (A_IsUnicode ? "W" : "A")
		, Ptr, addr, UInt, Size, UInt, 0x00000001|0x40000000, Str, Base64, UIntP, Req, "CDECL Int")
	Return Base64
}

ObjFromBase64(Base64) {
	DllCall("Crypt32.dll\CryptStringToBinary" (A_IsUnicode ? "W" : "A"), UInt, &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" (A_IsUnicode ? "W" : "A"), UInt, &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 if (k+0="")
			NumPut(-10,addr+0,"Char"),NumPut(sz:=StrPut(k,addr+9)*2,addr+1,"Int64"),addr+=sz+9
		else NumPut( InStr(k,".")?-9:k>4294967295?-8:k>65535?-6:k>255?-4:k>-1?-2:k>-129?-1:k>-32769?-3:k>-2147483649?-5:-7,addr+0,"Char")
			,NumPut(k,addr+1,InStr(k,".")?"Double":k>4294967295?"UInt64":k>65535?"UInt":k>255?"UShort":k>-1?"UChar":k>-129?"Char":k>-32769?"Short":k>-2147483649?"Int":"Int64")
			,addr+=InStr(k,".")||k>4294967295?9:k>65535?5:k>255?3:k>-129?2:k>-32769?3:k>-2147483649?5: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 if (v+0="")
		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
		else NumPut(InStr(v,".")?9:v>4294967295?8:v>65535?6:v>255?4:v>-1?2:v>-129?1:v>-32769?3:v>-2147483649?5:7,addr+0,"Char")
			,NumPut(v,addr+1,InStr(v,".")?"Double":v>4294967295?"UInt64":v>65535?"UInt":v>255?"UShort":v>-1?"UChar":v>-129?"Char":v>-32769?"Short":v>-2147483649?"Int":"Int64")
			,addr+=InStr(v,".")||v>4294967295?9:v>65535?5:v>255?3:v>-129?2:v>-32769?3:v>-2147483649?5: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 if (k+0="")
			sz+=StrPut(k)*2+9
		else sz+=InStr(k,".")||k>4294967295?9:k>65535?5:k>255?3:k>-129?2:k>-32769?3:k>-2147483649?5:9
		If IsObject(v)
			sz+=objects.HasKey(v)?9:RawObjectSize(v,buf,objects)+9
		else if (v+0="")
			sz+=(buf?obj.GetCapacity(k):StrPut(v)*2)+9
		else sz+=InStr(v,".")||v>4294967295?9:v>65535?5:v>255?3:v>-129?2:v>-32769?3:v>-2147483649?5: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
			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
}
По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

63

Re: AHK: Сохранение Массива в файл

В коллекции нужно. Выкладывай с описанием, комментариями и примером использования.

64

Re: AHK: Сохранение Массива в файл

Что описать и прокомментировать?
Пример приведён:

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
По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

65

Re: AHK: Сохранение Массива в файл

Представленная функция позволяет...
Код функции (где возможно - с комментариями).
Пример использования: сохраняем массив в файл, считываем массив из файла.

В общем представь, что ты через 20 лет всё забыл. Потом зашёл в Коллекцию, заглянул в тему и сразу вспомнил. Это сейчас смотришь на голый код и всё понятно. А после без комментариев не разберёшься.

66

Re: AHK: Сохранение Массива в файл

Имена ObjToBase64, ObjFromBase64 говорят за себя, в них "стандартный" код касаемый Base64. Так что не знаю что комментировать.

Пример использования: сохраняем массив в файл, считываем массив из файла.

Пример таков и есть, но:
В таком случае в описание можно добавить что сохранение и восстановление всё таки связано не с файлом, а со строкой. Строку уже можно сохранить и в текстовый файл, и в ключ ини файла, тут уже кому как удобно.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

67

Re: AHK: Сохранение Массива в файл

serzh82saratov пишет:

Так как функции RawObject, RawObjectSize, ObjLoad настолько же изменил насколько их понял (то есть оставил почти в оригинале), то хочу спросить не находит ли кто ошибок

Как ошибка, на лицо наличие рекурсии в них, если кто исправит, было бы понадёжнее.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

68

Re: AHK: Сохранение Массива в файл

Почему это ошибка?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

69 (изменено: serzh82saratov, 2017-03-07 20:40:55)

Re: AHK: Сохранение Массива в файл

Переполнение стэка?
Мало ли, большая вложенность массивов.
Может быть повлияет не очень большая вложенность, а большой размер вложенных массивов?

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

70

Re: AHK: Сохранение Массива в файл

Нет, там именно большая вложенность влияет. На практике такое вряд ли встретится. А заменять рекурсию циклом вещь довольно мозголомная, сам знаешь.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

71

Re: AHK: Сохранение Массива в файл

Твой ответ ждал, выложу на досуге.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

72

Re: AHK: Сохранение Массива в файл

serzh82saratov пишет:
(A_IsUnicode ? "W" : "A")

Это не обязательно.

serzh82saratov пишет:
UInt, &Base64

Тут ошибка, должно быть Ptr.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

73

Re: AHK: Сохранение Массива в файл

Поправил.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

74 (изменено: serzh82saratov, 2017-11-15 01:41:18)

Re: AHK: Сохранение Массива в файл

Нашёл ошибку, если ключ или значение - число, то удаляются пробелы. Удалил в коде строки записывающие числа как числа, теперь пишет как строку. Но в данном примере не пойму откуда в массиве берётся третий ключ "|11|  999|", в ObjLoad ведь 2 итерации.


#SingleInstance Force
#NoEnv

arr := {"  11":"888   ","11  ":"  999"}

Base64 := ObjToBase64(arr)

for k, v in ObjFromBase64(Base64)
	MsgBox, , Читаем полученное, % "|" k  "|"  v "|"

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
		; MsgBox, , % A_ThisFunc, % "|" k  "|"  v "|" 
	}
}

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
			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
		
		MsgBox, , % A_ThisFunc, % "|" k  "|"  obj[k] "|"
	}
	return obj
}
По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

75

Re: AHK: Сохранение Массива в файл

Намёк не понял.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

76 (изменено: serzh82saratov, 2017-11-15 16:21:18)

Re: AHK: Сохранение Массива в файл

Вроде так:


#SingleInstance Force
#NoEnv

arr := {"  11":"888   ","11  ":"  999"}
Base64 := ObjToBase64(arr)
for k, v in ObjFromBase64(Base64)
	MsgBox, , Читаем полученное, % "|" k  "|"  v "|"
	
B := ["Ivan", 345, "London"]
Base64 := ObjToBase64(B)
Obj := ObjFromBase64(Base64)
for k, v in Obj
	MsgBox % k " : " v

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


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 ~="S)\s") && (k + 0 != "")
				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
}
По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

77 (изменено: serzh82saratov, 2017-11-15 16:21:39)

Re: AHK: Сохранение Массива в файл

Заменил на это:

		else if NumGet(addr+0,"Char")= 10 {
			If !(k ~="S)\s") && (k + 0 != "")
				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 if NumGet(addr+0,"Char")= 10
			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
По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

78

Re: AHK: Сохранение Массива в файл

Баг нашёл.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

79

Re: AHK: Сохранение Массива в файл

Я не понял, можешь на примере кода, для функций из коллекции.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

80 (изменено: teadrinker, 2018-07-26 21:19:12)

Re: AHK: Сохранение Массива в файл

Если в скрипте установлена кодировка файлов, например UTF-8, то когда файл открывается с помощью f:=FileOpen(obj,"rw-rwd"), указатель находится не в нулевой позиции, а в позиции за BOM, в данном случае 3, и дамп записывается с третьего байта, в то время как читается он с нулевого, и скрипт зацикливается.

Баг уже исправлен.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

81

Re: AHK: Сохранение Массива в файл

Просто у меня в коллекции нет FileOpen, потому не понял в чём вопрос. А про f.Pos := 0 ты сам уже давно как то говорил, я с тех пор после FileOpen указатель всегда на ноль ставлю.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

82

Re: AHK: Сохранение Массива в файл

Если предполагается писать в RAW-формате, можно, как и предложено, указывать FileOpen(file, "w", "cp0").

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

83

Re: AHK: Сохранение Массива в файл

Ясно, просто у меня в коллекции всё переделано в строку base64, то бишь писать будем как текст, как бы тему создавал для того чтобы можно было писать массив ключом в обычный ини файл.
У меня по началу была проблема, я тогда всё переделал под строки, в смысле запись чисел производится как строки. Это конечно понижает производительность, но думаю не критично, и может оградить от большинства коллизий с большими числами, и сохранением каких то значений в первозданном виде, SetFormat чтобы не мешал например, или иными символами в них, как была проблема с пробелами. Хотя сейчас проверил тот пример на обновлённом коде из той темы, работает правильно.
Вообщем думаю оставить как есть, а для искушенных ссылка приведена.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

84

Re: AHK: Сохранение Массива в файл

Не знаю, будет ли это мнение уместно, но так же, очень удобным, да ещё и довольно универсальным, нашёл для себя использование класса JSON на этот же самый манер. Для перевода "туда" и "обратно", подобное простому:


ObjDump(o := "", fileName := "ObjDump") {
	if (IsObject( o )) {
		file := FileOpen(fileName, "w", "UTF-8")
		file.Write(JSON.Stringify( o ))
		file.Close()
		return true
	} file := FileOpen(fileName, "r", "UTF-8")
	content := JSON.Parse( file.Read() )
	file.Close()
	return content
}

Выглядит более очеловеченным и в текстовом редакторе можно поглядеть на него прямо как на понятную запись. Как считаете?

Да ещё, выглядит делом крайне полезным, добавить этот класс в коллекцию. С молчаливого согласия teadrinker, я его нещадно пользую в своих меркантильных делах, кто-то ещё, этим наверняка промышляет, а кто-то, юзает забугорные поделки, которые к прочему, не очень-то и корректны в некоторых случаях да и выглядят громоздко.

Добавьте пожалуйста. Поддержим отечественного производителя!

85

Re: AHK: Сохранение Массива в файл

Json можно использовать, но с некоторыми оговорками:

obj := [0xFF, 0xFFFF]
MsgBox, % JSON.Stringify(obj)

obj := ["0xFF", "0xFFFF"]
MsgBox, % JSON.Stringify(obj)

И ещё что-то подобное вроде было, сейчас уже не помню.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

86

Re: AHK: Сохранение Массива в файл

Да просто поместите это в комментарий в первых строках кода и делов то!
Предупреждён - значит вооружён!

87

Re: AHK: Сохранение Массива в файл

А эти символы должны возвращаться с наклонной чертой?

obj := ["`n`r	"]
MsgBox, % JSON.Stringify(obj)
По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

88

Re: AHK: Сохранение Массива в файл

Ну да, в JScript они так обозначаются. Кроме того, это и из исходного кода метода Stringify видно:

      for k, v in [["\", "\\"], [A_Tab, "\t"], ["""", "\"""], ["/", "\/"], ["`n", "\n"], ["`r", "\r"], [Chr(12), "\f"], [Chr(08), "\b"]]
         obj := StrReplace( obj, v[1], v[2] )
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

89

Re: AHK: Сохранение Массива в файл

А в JSON нет простых массивов?


obj := [,,"value"]
MsgBox, % obj := JSON.Stringify(obj)
По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

90

Re: AHK: Сохранение Массива в файл

Почему нет? Заполни все ключи, и будет "простой" массив.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

91

Re: AHK: Сохранение Массива в файл

teadrinker пишет:

Заполни все ключи

А это нельзя учесть в коде?

teadrinker пишет:

Ну да, в JScript они так обозначаются

А почему не всегда?


obj := ["0xFF	"]
MsgBox, % JSON.Stringify(obj)
По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

92

Re: AHK: Сохранение Массива в файл

serzh82saratov пишет:

А это нельзя учесть в коде?

И что должно быть в результате? В массивах array в JScript пропуски ключей не поддерживаются.

serzh82saratov пишет:

А почему не всегда?

По той же причине, что и

obj := ["0xFF   "]
MsgBox, % obj[1]*1

Скажем так, особенность восприятия AHK числовых и строчных значений.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

93

Re: AHK: Сохранение Массива в файл

teadrinker пишет:

пропуски ключей не поддерживаются.

Да, я думал что просто 1 и 2 равно пусто, но нет.

obj := [,,"value"]
MsgBox % obj.haskey(1)
teadrinker пишет:

особенность восприятия AHK числовых и строчных значений.

Так это вроде легко починить, после арифметики надо проверить пробел и табуляцию.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

94 (изменено: teadrinker, 2018-08-01 14:39:02)

Re: AHK: Сохранение Массива в файл

Можно, но не все проблемы решает:

obj := ["0xFF	"]
MsgBox, % str := JSON.Stringify(obj)
obj2 := JSON.Parse(str)

for k, v in obj2
   MsgBox, % "|" . v . "|"

obj := ["0xFF"]
MsgBox, % str := JSON.Stringify(obj)
obj2 := JSON.Parse(str)

for k, v in obj2
   MsgBox, % "|" . v . "|"

class JSON
{
   static JS := JSON._GetJScripObject()
   
   Parse(JsonString)  {
      try oJSON := this.JS.("(" JsonString ")")
      catch  {
         MsgBox, Wrong JsonString!
         Return
      }
      Return this._CreateObject(oJSON)
   }
   
   Stringify(obj)  {
      if IsObject( obj )  {
         isArray := true
         for key in obj
            if !( key = A_Index || isArray := false )
               break
            
         for k, v in obj
            str .= ( A_Index = 1 ? "" : "," ) . ( isArray ? "" : this.Stringify(k) . ":" ) . this.Stringify(v)

         return isArray ? "[" str "]" : "{" str "}"
      }
      else if (obj*1 && !RegExMatch(obj, "\s"))
         return obj
      
      for k, v in [["\", "\\"], [A_Tab, "\t"], ["""", "\"""], ["/", "\/"], ["`n", "\n"], ["`r", "\r"], [Chr(12), "\f"], [Chr(08), "\b"]]
         obj := StrReplace( obj, v[1], v[2] )
      
      while RegexMatch( obj, "[^\x20-\x7e]", key )  {
         str := Asc( key )
         val := "\u" . Chr( ( ( str >> 12 ) & 15 ) + ( ( ( str >> 12 ) & 15 ) < 10 ? 48 : 55 ) )
               . Chr( ( ( str >> 8 ) & 15 ) + ( ( ( str >> 8 ) & 15 ) < 10 ? 48 : 55 ) )
               . Chr( ( ( str >> 4 ) & 15 ) + ( ( ( str >> 4 ) & 15 ) < 10 ? 48 : 55 ) )
               . Chr( ( str & 15 ) + ( ( str & 15 ) < 10 ? 48 : 55 ) )
         obj := StrReplace(obj, key, val)
      }
      Return """" obj """"
   }
   
   GetFromUrl(url, body := "", contentType := "", userAgent := "")  {
      ; в случае удачи будет возвращена строка, в случае ошибки — массив с одним элементом-строкой с описанием ошибки
      try  {
         XmlHttp := ComObjCreate("Microsoft.XmlHttp")
         XmlHttp.Open("GET", url, false)
         ( contentType && XmlHttp.SetRequestHeader("Content-Type", contentType) )
         ( userAgent && XmlHttp.SetRequestHeader("User-Agent", userAgent) )
         XmlHttp.Send(body)
      }
      catch e
         Return ["Error!`n" . e.Message]
      status := XmlHttp.Status
      Return status = 200 ? XmlHttp.ResponseText : ["Error! Status: " . status . ", ResponseText: " . XmlHttp.ResponseText]
   }

   _GetJScripObject()  {
      VarSetCapacity(tmpFile, ((MAX_PATH := 260) - 14) << !!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
   }
}

AutoHotkey не может наверняка отличить строку от числа.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

95

Re: AHK: Сохранение Массива в файл

Тогда нужно учитывать, что любая запись шестнадцатеричного вида будет восприниматься как число, приводимое к десятичному виду, если в ней нет хотя-бы одного словесного символа, или символа окончания, или новой строки, а пробелы и табы ПЕРЕД и ЗА которыми ничего не следует - просто обрезаются в любых количествах, так как их присутствие не нагружает запись смыслом.

96

Re: AHK: Сохранение Массива в файл

Да, как-то так можно. Попозже могу выложить.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

97 (изменено: serzh82saratov, 2018-08-01 21:06:48)

Re: AHK: Сохранение Массива в файл

KusochekDobra пишет:

если в ней нет хотя-бы одного словесного символа, или символа окончания, или новой строки

С ними вроде математика и так пусто вернёт. Только пробелы и табы не влияет на математику. Но думаю obj ~= "\s" самое то.

KusochekDobra пишет:

ПЕРЕД и ЗА которыми ничего не следует - просто обрезаются в любых количествах, так как их присутствие не нагружает запись смыслом.

А это зачем? Если они туда зачем то попали, значит это надо было, и это строка, а строки надо бы сохранять в оригинале.

obj*1

А если ноль?

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

98

Re: AHK: Сохранение Массива в файл

Пробелы тоже думаю, надо сохранять, пусть пользователь решает, нужны они, или нет.

serzh82saratov пишет:

А если ноль?

Да, нужно на пустоту проверять, уже исправил у себя.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

99

Re: AHK: Сохранение Массива в файл

Хотел было глупость написать, что, если JSON пользуют для передачи данных, то он должен по идее так себя и вести, но, действительно в "тру-js" - сохраняются все табы и пробелы:

console.log(JSON.stringify({empty5Space: '   5  ', empty5Tab: '			5		'}))

И я ещё донышко-постигающее, так что сильно палками не бейте, коллеги! Какие-то моменты мне пока не ведомы.
Спасибо за ваше компетентное участие!