Jump to content

Binary Write/Read example script


Recommended Posts

(Edited from original.  Please note that I AM NOT AN AUTOIT EXPERT.  I write code using Autoit frequently but I am no expert, especially when it comes to I/O.  So any remarks that start with "Why did you..." can be answered by referring to the first sentence.  This project was done in Autoit because of an interface I built to display the data.)

Attached is a program and ascii input file I wrote to read stock price data, convert it to binary and then read it back into the program in binary.  The goal was to show increased performance for reading the files in binary and provide a demo on how to read/write binary for int32, int64, double and strings for anyone who might find it helpful.  The results on my PC show the following:

Time to read ascii file only: 456.981951167202
Ascii read & process time: 6061.83075631701
Binary write file time: 14787.9184635239
Time just to read binary file: 42.418867292311
Binary read and process time: 4515.16129830537

A couple things to note:

1) The 32 MB ascii file took 10x longer to read than the 15 MB binary file.  Not entirely sure why.  Both were read into a buffer.

2) The Binary write takes a long time but I made no effort to optimize this because the plan was to write this file one time only so I don't mind if it takes longer to write this file.  I care much more about how long it takes to read the file because I will be reading it many times.

3) There was a modest gain in converting the ascii file to binary in terms of file size and reading speed.

So big picture... not sure it's worth the effort to convert the files to binary even though most of the data is numerical data in the binary file.  That was actually surprising as I expected there would be more of a difference.  Any ideas on how to get the binary data to read at a faster rate would be great.

 

binary.au3

2019_02_08.zip

Edited by Stew
new version
Link to post
Share on other sites

Sorry but this is useless bloatware.

Edited by jchd

This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Link to post
Share on other sites
5 hours ago, jchd said:

Sorry but this is useless bloatware.

Based upon this naive response I'm guessing you never had to deal with massive amounts of data.  For anyone having to read large data files it is very important to be able to read/write binary.  I have massive amounts of ascii stock price data that takes long periods to read as ascii files.  By converting the files to binary my software can now read them in a fraction of the time it previously required.  

Having seen how many posts there are on these forums for programmers trying to figure out how to read/write binary using Autoit I expect it will be helpful to many others as well.  If not, no problem.  Few photons and electrons were injured in the creation of this forum posting.

Link to post
Share on other sites

he is referring to the fact that this functionality already exists in AutoIt proper. BinaryToString and StringToBinary are already an established thing. the Help file also details how to use them. Anyone can write a loop that reads in data and writes out binary with such functions. This was kind of like reinventing the wheel I guess. still, thanks for the effort and, if it works well for you, then you must be doing something right! happy programming.

Edited by Earthshine

My resources are limited. You must ask the right questions

 

Link to post
Share on other sites

Thanks for your response.  I think a detailed explanation may be helpful.  Let's go through an example that may make it clear the importance of not treating numerical data as a string.

Let's say I have a large number:  2141231231  (10 characters)

I have two options to write that number to a file... as a string of 11 bytes (written either in ascii or binary with a deliminator) or as an Int32 which is 4 bytes (written in binary).  The BinaryToString and StringToBinary will treat this as 11 bytes so the file size is larger but admittedly dependent on the number of characters in the number.  The file size could potentially be smaller if the numerical data on average was made up of numbers from -9 to 99 (remember, still need a 1 char deliminator). 

But that's not the real problem.  After reading in this data as a string you still need to convert this string to a number so that it can be used in mathematical calculations.  The string is of no value for calculations.  That requires several steps with a computational penalty for each step.

For every data point I read in binary as a string I first have to use BinaryToString to get the data in string format, I then have to use StringSplit to separate the large string into individual strings for each number and finally I have to use the Number algorithm to convert the string into a number.  When you have millions of data points this is very slow and unnecessary.  Much better to write the data in binary as an Int32, Int64 or Double and read it in binary as the same data type.  By doing that I eliminate BinaryToString, StringSplit and Number from the process.

For small file sizes this is a non-issue in regards to time savings although I think it's actually easier to read/write these files in the method I outlined than use multiple steps to convert between strings and numbers.  But for large datasets the time savings in reading these files in the way I outlined is significant.  You definitely don't want to read/write numbers as a string whenever dealing with a lot of data.

Hope that helps.

Link to post
Share on other sites

I didn't misunderstand you--there are other functions to change string to int or floats too before writing out to binary. I understand what you are doing but it can be done other ways, but whatever--you do your thing

My resources are limited. You must ask the right questions

 

Link to post
Share on other sites
  • Moderators
2 hours ago, Stew said:

Based upon this naive response I'm guessing you never had to deal with massive amounts of data. 

Based on this naive response, you have made everyone on this forum who knows the depth of jchd's technical knowledge laugh.

"Profanity is the last vestige of the feeble mind. For the man who cannot express himself forcibly through intellect must do so through shock and awe" - Spencer W. Kimball

How to get your question answered on this forum!

Link to post
Share on other sites

Well maybe jchd's technical knowledge is good but communication skills could use some work.  I'm guessing based upon his/her response that I probably didn't hurt their feelings too much but it's very nice that you stood up for them.  

Earthshine, actually I think there is still some misunderstanding...  I am not converting strings to int or floats before writing out to binary.  My data is already in int and float format in the computer memory as that is the form I need it in to do computations.  I just want to write it out in that format without going through a string in the process as that is an unnecessary and computationally expensive step.  The suggestion to use BinaryToString and StringToBinary would introduce this  unnecessary step.  I want to read/write as Int32, Int64 and Double directly and that is the subject of the code I posted.

If anyone has a better way to read/write numerical data in the most computationally efficient manner possible, please post it here.  My only goal is to minimize computational and i/o time in reading large numerical datasets.  If I'm re-inventing the wheel then I (and I suspect many others) have missed the posting of the wheel somewhere on this forum or in the help files.  Please tell me where you've hidden the wheel.  I'd be thrilled if someone had an even faster way to read/write large files of numerical data than the method I came up with so please post code if you  have it.  I for one would use your code.

Link to post
Share on other sites

I must apologize for my cryptic answer, hastily writen. It wasn't meant to be rude to you, just pointing out that such code isn't a valuable, efficient solution.

Quote

I have massive amounts of ascii stock price data that takes long periods to read as ascii files.  By converting the files to binary my software can now read them in a fraction of the time it previously required.

I feel this now turns out as a code optimization request, rather than a failed demo that plain vanilla code is inferior.

I gently suggest you open a new thread in General Help forum with a significant sample of input data and your requirements for processing. I strongly suspect there are faster regular ways to process text (ASCII) data than convert the wole thing to binary then extract the wanted pieces out of a large chunk of converted binary.

The goal of most of the fora here is to maximize usefulness of AutoIt-based code. So we're fully spot-on and there is a number of seasonned contributors here willing to provide as much help as possible.

This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Link to post
Share on other sites

jchd, thanks for your comments.  I'm actually not requesting any code optimization.  I'm also not suggesting the plain vanilla code is inferior.  Autoit is an incredible tool as is.  I was just trying to contribute some code that other programmers might find helpful.  I'm certain you could make autoit read ascii files faster with some tweaking but it won't compete with reading the same data in binary format.  It's simply impossible to do when you have to convert one using several steps and you don't have to convert the other.  So I would not submit anything to the General Help forum that I know has no chance at success.  Hopefully everyone recognizes this and won't waste time trying to do the impossible.  Reading numerical data in binary will ALWAYS be much faster than reading it in ascii.

So hopefully this series of blog posts makes things clear.  The sample code I submitted in the first post is ideally suited for instances where:

1) The data files are large

2) The data is primarily numerical

3) The data files need to be read several times

These set of criteria are actually quite common in with people doing research (like myself) and If these criteria are met then it's better to convert the files to binary one time and only read them in binary format going forward.  The sample code I submitted can be used to accomplish this goal.

That being said, the code is incredibly simple and can be used even if the files are not large and are not entirely numerical.  As long as you are careful to read and write the data in the same way it will work for any file and ALWAYS be faster than reading the same set of data in an ascii file.  

Again, I was just trying to help other programmers.  I suspect there will be programmers who need this for their research but even if I'm wrong about that at least I finally figured it out so I can use it in my own research.   I have yet to see a forum post or example code explaining how to read and write all types of data in binary using autoit.  Now there is 1.

Link to post
Share on other sites

Forgot another application.  If you are not dealing with large amounts of data but do have an application that does a lot of I/O to disk and some of the data is numerical data then you want to do that I/O in binary due to the increased speed.  If the data is entirely string data then you will probably not see a significant change in speed between ascii and binary I/O.

Link to post
Share on other sites

If/when I have to process a huge lot of numerical data provided in ASCII (for instance gazillions of points and other data from some geodesic source) I build a database from the source.

This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Link to post
Share on other sites
On 2/12/2019 at 6:43 PM, Stew said:

I wrote this sample script to help anyone trying to read and write binary files

I believe this is what you ended up using as a solution for the question of your first posting back in '15
A file is a file that is a file, if that makes any sense. Changing the delimitation format to a more useful one for the case makes sense.
As the above post say, using a standard database may be better.
Standardized formats are peer reviewed and helps oneself from reinventing wheels.
PS: By posting, one clarifies concepts. We all learn at the end. Thanks for sharing your ideas and findings.

Link to post
Share on other sites

argumentum, you are correct.  I haven't looked at this code in some time and decided this week to tackle the problem again and this was the solution.  I have just been reading the ascii files instead.  If you search the forum you will find I am not alone in trying to read/write binary numerical data.  There are a several posts on this topic over several years. 

I have updated the original post above with the full code I use to read the stock price data in ascii, write it in binary and read it back in using binary. I included an ascii file to read in the event anyone wants to mess with the code.

Link to post
Share on other sites
3 hours ago, Stew said:

If you search the forum you will find I am not alone in trying to read/write binary numerical data

Again, a file is a file that is a file, if that makes any sense. And it usually does not. Even a folder is a file with a "Directory" attribute.
All files are binary. Period. The ASCII table is an agreed standard.

The file you provided is a comma delimited file, that could have been written in a way to know that is a string or number, by encapsulating the strings with " symbols and those not encapsulated would then be numbers. But the file generator did not do this, as is not really needed unless there is a comma in the string.

So if you have a zero, in binary you'd write 0x00 ?, what if it is a real ?. CPUs work with integers. Long story short, your concept of binary read/write and what a character represents, is misconceptualized. If you feel you would welcome help, help is afoot.

4 hours ago, Stew said:

I am not alone in trying to read/write binary numerical data

There are many that are clueless. Read up. Right now, you may not welcome this posting but once you incorporate the proper knowing, it'll make sense.
I write this in humble. I've had your views, before.

Link to post
Share on other sites

Although I'm no Autoit expert, I've been writing complex software for computational fluid dynamics, 3D computer modeling, computer-aided diagnosis, natural language processing, etc. for 30 years.  I've also written code that manipulates bits for 3D modeling, switch endian for reading DICOM files, etc.  So I have a very good understanding of the way data is represented in a computer's memory and stored on a hard drive.  We can get into esoteric discussions about whether data is real, binary, etc., etc. but obviously it's all binary.  Most of us simply refer to the type of data we are working with and I'm primarily working with real numbers (float, double) and integers (int, long) for this project.

If you really want to be helpful then suggest a faster method to do I/O in this application and I'll test your ideas.  Or post some code.  That would be even better!  I don't care if you want to write ascii (text, strings or whatever you want to call it), binary, martian, etc.  I just want it to be as fast as possible getting the data from the hard drive into the RAM and associated with the proper variables.  I acknowledge that shoving all the data into a database for access is probably the best solution but this is just a fun project for me so I want to keep it as simple as possible.  I'm not excited about introducing a database.  

Link to post
Share on other sites
  • 10 months later...

Here is one quick DICOM image reading folder opening folder reading software. Because of the endian the tags are reversed. If images are not in a subfolder, that is opened instead of the folder.

The idea is to convert the binary parts to hex, and use regex to search and replace.

There is probably a better way to do this, but this has worked for me, hope this helps

DICOMTOOL.png

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By Pickpocketz88
      Func _Binary($Int) ;Uncomment To Only Accept Integers #cs If IsInt($Int) = 0 Then Return 0 EndIf #ce If $Int < 0 Then ;Negative Numbers Will Break The Function Return 0000 EndIf Local $Integer = $Int Dim $Bin[1] = [Mod($Integer, 2)] Local $Counter = 1 Do $Integer = Floor($Integer / 2) _ArrayAdd($Bin, Mod($Integer, 2)) Until $Integer = 0 _ArrayReverse($Bin) ;Reverses The Array Because As Is, The Product Is Backwards ;A Loop To Remove Any Preceding 0's or Add 0's To Keep At Least Four Digits Select Case $Int <= 1 $Integer = "00" & _ArrayToString($Bin, "") Case $Int = 2 Or $Int = 3 $Integer = "0" & _ArrayToString($Bin, "") Case $Int >= 8 $Integer = StringTrimLeft(_ArrayToString($Bin, ""), 1) Case Else $Integer = _ArrayToString($Bin, "") EndSelect ;You Can Comment It Out Without Anything Else Having A Problem Return $Integer EndFunc I made this because I was writing something that I could use to play with Bitwise Operations and using Binary() by itself wasn't helping.
      It's very basic and will only take positive integers because that's all I needed but I'm sure with a little tweaking you could make it fit with negative and float types.
      It returns a string essentially but doesn't pose a problem when just changing numbers into binary digits.
      Example: If you were to do _Binary(5) you would get "0101" and _Binary(8) would return "1000"
      Between this last sentence and here I've changed this about a half dozen times to refine it a bit because without it checking if your number is < 0 it would break if a negative number was inserted and it wouldn't even have a problem if you put in Float Values, Regular or Special Characters but that negative value will do the trick lol.
      Anyway, I hope someone finds some use of this and thank you for reading!
      -Pick
    • By EmilyLove
      I have a string containing the full path of an executable and an array of executables without their paths. I am trying to compare the string to the list in the array and if a match is found, remove it from the array. The entry get removed from the array successfully, and after checking its return result, uses it to update the ubound if it succeeded, but it doesn't want to update to the new value. Any ideas what I am doing wrong? It acts like it is read-only.
      #include <Array.au3> #include <File.au3> Local $sApp_Exe = "F:\App\Nextcloud\nextcloud.exe" Local $aWaitForEXEX = [3, "Nextcloud.exe", "nextcloudcmd.exe", "QtWebEngineProcess.exe"] For $h = 1 To $aWaitForEXEX[0] If StringInStr($sApp_Exe, $aWaitForEXEX[$h]) <> 0 Then $iRet = _ArrayDelete($aWaitForEXEX, $h) If $iRet <> -1 Then $aWaitForEXEX[0] = $iRet ;this line doesn't work. $aWaitForEXEX[0] doesn't update and shortly gives Error: Array variable has incorrect number of subscripts or subscript dimension range exceeded.: _ArrayDisplay($aWaitForEXEX) EndIf Next  
    • By Colduction
      Hi AutoIt Programmers, i wanna figure out how to use Binary functions in C# like:

      BinaryMid
      BinaryLen
      IsBinary and other basic ones were too ez, but those two were hard to noob like me.

      I appreciate for your helps/hints.
    • By Chimp
      This "cow" seems funny to me,
          
      At this link (https://dodona.ugent.be/en/activities/1605325419/#) a brief rough description of what this script can do (sorry for the laziness, but that description may be fine).
      You can use the _CowSayWin() function to display a message formatted in a comic along with an ascii art figure in a standalone window,
      or
      you can use _String_CowSay() function to format a plain string in a comic along with an ascii art figure and have it returned in a string for your own purposes, you will probably use it in Consolewrite () or whatever ...
      The script makes use of the _StringSize() function written by @Melba23 (thanks Melba) of the StringSize.au3 udf that you can extract from the zip file located at this link: https://www.autoitscript.com/forum/topic/114034-stringsize-m23-new-version-16-aug-11/. You have to save that udf file in the same directory along with this script.
      It also makes use of the _WinSetClientSize() function written by @KaFu. (thanks kafu) This function is already built into the main script.
      I hope you have fun
      #include <FontConstants.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include <WinAPI.au3> #include <WinAPISys.au3> #include <array.au3> #include <String.au3> #include "StringSize.au3" ; <-- https://www.autoitscript.com/forum/topic/114034-stringsize-m23-new-version-16-aug-11/ _Example() Func _Example() SRandom(@SEC) Local $hCowWin, $aMsg = 0 Local $sMessage, $iWidth, $iClipart, $iTextAlig Local $aMessages[] = ["Bottled water companies don’t produce water, they produce plastic bottles.", _ "The greatest glory in living lies not in never falling, but in rising every time we fall.", _ "Your time is limited, so don't waste it living someone else's life. " & _ "Don't be trapped by dogma which is living with the results of other people's thinking.", _ "Insanity is doing the same thing over and over again and expecting different results", _ "The way to get started is to quit talking and begin doing."] For $i = 1 To 6 $sMessage = $aMessages[Random(0, UBound($aMessages) - 1, 1)] $iWidth = Random(21, 90, 1) $iClipart = Random(0, 3, 1) $iTextAlign = 1 ; Random(0, 2, 1) Left and right alignments are a bit ugly. ; they are allowed however if you need them ; ; You can use the _CowSayWin() function to create the "cowsay" message in a window $hCowWin = _CowSayWin($sMessage, $iWidth, $iClipart, $iTextAlign) ; ; or you can use the _String_CowSay() function to get a string of the "cowsay ascii clipart" ; so that you can use it however you like, probably in a Consolewrite () for example ... ConsoleWrite(_String_CowSay($sMessage, $iWidth, $iClipart, $iTextAlign) & @CRLF) While 1 $aMsg = GUIGetMsg($GUI_EVENT_ARRAY) Switch $aMsg[1] Case $hCowWin Switch $aMsg[0] Case -3 ; $GUI_EVENT_CLOSE ExitLoop EndSwitch EndSwitch WEnd GUIDelete(HWnd($hCowWin)) Next EndFunc ;==>_Example ; #FUNCTION# ==================================================================================================================== ; Name ..........: _CowSayWin ; Description ...: Display a message in a standalone windows formatted in a balloon along with an ascii art figure ; Syntax ........: _CowSayWin($sMsg[, $iBoxLen = 21[, $iShape = 0[, $iAlign = 1]]]) ; Parameters ....: $sMsg - a string value. The message to display (in a single line without @cr and or @lf) ; $iBoxLen - [optional] an integer value. Default is 21. ; The wanted width of the Box contining the message ; $iShape - [optional] an integer value. Default is 0. ; The index of the ascii art figure to be displayed along with the message. ; Available values are: ; 0 -> a cow ; 1 -> a sandwich-man ; 2 -> the penguin Tux ; 3 -> a hanging monkey ; ..... to be continued (maybe) ; $iAlign - [optional] an integer value. Default is 1. ; How to justify the string within the frame, that is: ; 0 -> left justified ; 1 -> center justified (default) ; 2 -> right justified ; Return values .: The handle of the created window ; Author ........: Gianni Addiego (Chimp) ; Modified ......: ; Remarks .......: ; Related .......: ; Link ..........: ; Example .......: No ; =============================================================================================================================== Func _CowSayWin($sMsg, $iBoxLen = 21, $iShape = 0, $iAlign = 1) If $iBoxLen < 21 Then $iBoxLen = 21 Local $iSize = 12 Local $iWeight = $FW_NORMAL Local $iAttrib = $GUI_FONTNORMAL Local $sFont = "Courier new" Local $sSay = _String_CowSay($sMsg, $iBoxLen, $iShape, $iAlign) Local $aMsgReturn = _StringSize($sSay, $iSize, $iWeight, $iAttrib, $sFont) Local $iXpos = (@DesktopWidth - $aMsgReturn[2]) / 2 If $iXpos < 0 Then $iXpos = 0 Local $iYpos = (@DesktopHeight - $aMsgReturn[3]) / 2 If $iYpos < 0 Then $iYpos = 0 Local $hCow = GUICreate("Cowsay", -1, -1, $iXpos, $iYpos, -1, BitOR($WS_EX_TOOLWINDOW, $WS_EX_TOPMOST)) ;0x94C803C5, 0x00010101) ; , $WS_EX_DLGMODALFRAME) ;0x94C803C5, 0x00010101) ; Style & ExStyle same as msgbox GUISetFont($iSize, $FW_NORMAL, $GUI_FONTNORMAL, $sFont) _WinSetClientSize($hCow, $aMsgReturn[2], $aMsgReturn[3]) GUICtrlCreateLabel($sSay, 0, 0, $aMsgReturn[2], $aMsgReturn[3]) GUISetState(@SW_SHOW, $hCow) #cs While 1 Switch GUIGetMsg() Case -3 ; $GUI_EVENT_CLOSE ExitLoop EndSwitch WEnd #ce Return $hCow EndFunc ;==>_CowSayWin ; By kafu ; https://www.autoitscript.com/forum/topic/201524-guicreate-and-wingetclientsize-mismatch/?do=findComment&comment=1446141 Func _WinSetClientSize($hWnd, $iW, $iH) Local $aWinPos = WinGetPos($hWnd) Local $sRect = DllStructCreate("int;int;int;int;") DllStructSetData($sRect, 3, $iW) DllStructSetData($sRect, 4, $iH) _WinAPI_AdjustWindowRectEx($sRect, _WinAPI_GetWindowLong($hWnd, $GWL_STYLE), _WinAPI_GetWindowLong($hWnd, $GWL_EXSTYLE)) WinMove($hWnd, "", $aWinPos[0], $aWinPos[1], $aWinPos[2] + (DllStructGetData($sRect, 3) - $aWinPos[2]) - DllStructGetData($sRect, 1), $aWinPos[3] + (DllStructGetData($sRect, 4) - $aWinPos[3]) - DllStructGetData($sRect, 2)) EndFunc ;==>_WinSetClientSize ; #FUNCTION# ==================================================================================================================== ; Name ..........: _StringToColumn ; Description ...: passing a (long) string and a value, it returns that same string ; formatted in a column as wide as the value (string is split by @CRs). ; Whenever possible, it tries not to break the words but to split ; lines in between two words ; Syntax ........: _StringToColumn($sString[, $x = 21]) ; Parameters ....: $sString - a string value. The string to format ; $iColumnWidth - [optional] an integer value. Default is 21. ; The wanted width of the text column ; Return values .: The string formatted as required ; Author ........: Gianni Addiego (Chimp) ; Modified ......: ; Remarks .......: ; Related .......: ; Link ..........: ; Example .......: No ; =============================================================================================================================== Func _StringToColumn($sString, $iColumnWidth = 21) If $iColumnWidth < 1 Then $iColumnWidth = 1 Local $iPreviousSplit = 1 Local $i = $iColumnWidth While $i <= StringLen($sString) $iSplitPoint = StringInStr($sString, " ", 0, -1, $i + 1) If $iSplitPoint = 0 Or $iSplitPoint <= $iPreviousSplit Then $iSplitPoint = $i $sString = StringLeft($sString, $iSplitPoint) & @CR & StringMid($sString, $iSplitPoint + 1) $i = $iSplitPoint + 1 Else $sString = StringReplace($sString, $iSplitPoint, @CR) $i = $iSplitPoint EndIf $iPreviousSplit = $iSplitPoint $i += $iColumnWidth WEnd If StringRight($sString, 1) = @CR Then $sString = StringTrimRight($sString, 1) Return $sString EndFunc ;==>_StringToColumn ; #FUNCTION# ==================================================================================================================== ; Name ..........: _StringToFrame ; Description ...: places borders only to the left and to the right of the passed string block ; Syntax ........: _StringToFrame($sStr, $iFrameWidth[, $iAlign = 1[, $sV = "|"]]) ; Parameters ....: $sStr - The string to format; multiline string must be splitted by a @cr. ; $iFrameWidth - wanted Width of the frame ; If the desired width is less than the length of the string, the exceeding part is cut off ; If the desired width is wider than the length of the string, spaces are added ; $iAlign - [optional] an integer value. Default is 1. ; The string is justified within the frame based on the value of the $iAlign variable, that is: ; 0 -> left justified ; 1 -> center justified (default) ; 2 -> right justified ; $sV - [optional] a string value. Default is "|". ; This is the character used to draw the two vertical edges ; Return values .: The formatted string ; Author ........: Gianni Addiego (Chimp) ; Modified ......: ; Remarks .......: ; Related .......: ; Link ..........: ; Example .......: No ; =============================================================================================================================== Func _StringToFrame($sStr, $iFrameWidth, $iAlign = 1, $sV = "|") ; $iAlign: 0=Left; 1=Center; 2=Right If $iFrameWidth < 1 Then $iFrameWidth = 1 Local $a = StringSplit($sStr, @CR, 2) ; 2 = $STR_NOCOUNT For $i = 0 To UBound($a) - 1 Switch $iAlign Case 1 ; Center string $a[$i] = $sV & _StringSetLen(_StringCenter($a[$i], $iFrameWidth), $iFrameWidth) & $sV Case 2 ; Align to right $a[$i] = $sV & _StringSetLen($a[$i], $iFrameWidth * -1) & $sV Case Else ; otherwise Align to left $a[$i] = $sV & _StringSetLen($a[$i], $iFrameWidth) & $sV EndSwitch Next Return _ArrayToString($a, @CR) EndFunc ;==>_StringToFrame ; passing a string and a value it returns that string with a len as required ; By Gianni Addiego Func _StringSetLen($sString, $iWantedLen = 1, $sFillChr = " ") If $iWantedLen = 0 Then Return "" Local $iLen = StringLen($sString) Local $iKeepLeft = $iWantedLen > 0 ; else keep the right side of the string $iWantedLen = Abs($iWantedLen) If $iLen >= $iWantedLen Then ; reduce the string length If $iKeepLeft Then Return StringLeft($sString, $iWantedLen) Else Return StringRight($sString, $iWantedLen) EndIf Else ; add chars to the string to reach the wanted len If $iKeepLeft Then Return $sString & _StringRepeat($sFillChr, $iWantedLen - $iLen) Else Return _StringRepeat($sFillChr, $iWantedLen - $iLen) & $sString EndIf EndIf EndFunc ;==>_StringSetLen ; place a string in the middle of a given space ; By Gianni Addiego Func _StringCenter($sString, $iSpace) Local $iLen = StringLen($sString) $iHloc = Int($iSpace / 2) - Int($iLen / 2) If $iHloc < 0 Then Return StringMid($sString, Abs($iHloc) + 1, $iSpace) Else Return _StringRepeat(" ", $iHloc) & $sString EndIf EndFunc ;==>_StringCenter ; #FUNCTION# ==================================================================================================================== ; Name ..........: _String_CowSay ; Description ...: Formats a string in a balloon along with an ascii art figure ; Syntax ........: _String_CowSay($sMsg[, $iBoxLen = 21[, $iShape = 0[, $iAlign = 1]]]) ; Parameters ....: $sMsg - a string value. The String to format (in a single line without @cr and or @lf) ; $iBoxLen - [optional] an integer value. Default is 21. ; The wanted width of the Box contining the message ; $iShape - [optional] an integer value. Default is 0. ; The index of the ascii art figure to be displayed along with the message. ; Available values are: ; 0 -> a cow ; 1 -> a sandwich-man ; 2 -> the penguin Tux ; 3 -> a hanging monkey ; ..... to be continued (maybe) ; $iAlign - [optional] an integer value. Default is 1. ; How to justify the string within the frame, that is: ; 0 -> left justified ; 1 -> center justified (default) ; 2 -> right justified ; Return values .: The passed string formatted in the required format. ; Author ........: Gianni Addiego (Chimp) ; Modified ......: ; Remarks .......: ; Related .......: ; Link ..........: ; Example .......: No ; =============================================================================================================================== Func _String_CowSay($sMsg, $iBoxLen = 21, $iShape = 0, $iAlign = 1) ; minimum $iBoxLen is 21 If $iBoxLen / 2 = Int($iBoxLen / 2) Then $iBoxLen += 1 If $iBoxLen < 22 Then $x = 0 Else $x = Ceiling(($iBoxLen - 21) / 2) EndIf Local $sS = _StringRepeat(" ", $x), $sT = _StringRepeat("~", $x) Local $sHeader, $sFooter Switch $iShape Case 1 $sHeader = _ $sS & " \|||/" & @CRLF & _ $sS & " (o o)" & @CRLF & _ "," & $sT & "oo0~~~~~~(_)~~~~~~~~~" & $sT & "," & @CRLF ; header $sFooter = _ "'" & $sT & "~~~~~~~~~~~~~~~~~~oo0" & $sT & "'" & @CRLF & _ ; footer $sS & " |__|__|" & @CRLF & _ $sS & " || ||" & @CRLF & _ $sS & " oo0 0oo" Case 2 $sHeader = _ "," & $sT & "~~~~~~~~~~~~~~~~~~~~~" & $sT & "," & @CRLF ; header $sFooter = _ "'~~~~~~~~~~~~~~~~~~~~~" & $sT & $sT & "'" & @CRLF & _ " \ .--." & @CRLF & _ " \ |o_o |" & @CRLF & _ " |:_/ |" & @CRLF & _ " // \ \" & @CRLF & _ " (| | )" & @CRLF & _ " /'\_ _/`\" & @CRLF & _ " \___)=(___/" Case 3 $sHeader = _ "," & $sT & "~~~~~~~~~~~~~~~~~~~~~" & $sT & "," & @CRLF ; header $sFooter = _ "'" & $sT & "oo0~~~~~~~~~~~~~~~0oo" & $sT & "'" & @CRLF & _ ; footer $sS & " \\ //" & @CRLF & _ $sS & " > \ \\|||// / <" & @CRLF & _ $sS & " > \ _ _ / <" & @CRLF & _ $sS & " > \ / \ / \ / <" & @CRLF & _ $sS & " > \\_o_o_// <" & @CRLF & _ $sS & " > ( (_) ) <" & @CRLF & _ $sS & " >| |<" & @CRLF & _ $sS & " / |\___/| \" & @CRLF & _ $sS & " / (_____) \" & @CRLF & _ $sS & " / o \" & @CRLF & _ $sS & " ) ___ (" & @CRLF & _ $sS & " / / \ \" & @CRLF & _ $sS & " ( / \ )" & @CRLF & _ $sS & " >< ><" & @CRLF & _ $sS & " ///\ /\\\" & @CRLF & _ $sS & " ''' '''" Case Else $sHeader = _ "," & $sT & "~~~~~~~~~~~~~~~~~~~~~" & $sT & "," & @CRLF ; header $sFooter = _ "'~~~~~~~~~~~~~~~~~~~~~" & $sT & $sT & "'" & @CRLF & _ " \ ^__^" & @CRLF & _ " \ (oo)\_______" & @CRLF & _ " (__)\ )\/\" & @CRLF & _ " ||----w |" & @CRLF & _ " || ||" EndSwitch Return $sHeader & _StringToFrame(_StringToColumn($sMsg, $iBoxLen), $iBoxLen, $iAlign) & @CRLF & $sFooter EndFunc ;==>_String_CowSay  
    • By kovlad
      My solution is to write nested arrays without copying.
      The problem was described hier.
       
      Function:
      #include <Array.au3> ; #FUNCTION# ==================================================================================================================== ; Name ..........: _ArrayNestedSet ; Description ...: Assigns a value to an element of a nested 1D array. ; Syntax ........: _ArrayNestedSet(ByRef $aArray, $vIndex, $vValue) ; Parameters ....: $aArray - an array of arrays. ; $vIndex - an index or 1d-array of indexes; ; a size if $vValue not defined (zero to delete). ; $vValue - a value (create, resize or delete if not defined). ; ; Return values .: on success - 1 ; @extended - nesting level of operation ; on failure - 0 ; @extended - nesting level of error ; @error = 1 - invalid array ; @error = 2 - invalid index ; Author ........: ; Modified ......: kovlad ; Remarks .......: ; Related .......: ; Link ..........: https://www.autoitscript.com/forum/topic/185638-assign-a-value-to-an-array-in-array-element/ ; https://www.autoitscript.com/trac/autoit/ticket/3515?replyto=description ; Example .......: Yes ; =============================================================================================================================== Func _ArrayNestedSet(ByRef $aArray, $vIndex, $vValue = Default) Local $extended = @extended + 1 If IsArray($vIndex) Then If UBound($vIndex, 0) <> 1 Then _ Return SetError(2, $extended) If UBound($vIndex) > 1 Then If UBound($aArray, 0) <> 1 Then _ Return SetError(1, $extended) ; keep index for this array Local $i = $vIndex[0] If $i < 0 Or UBound($aArray) <= $i Then _ Return SetError(2, $extended) ; delete index of this array _ArrayDelete($vIndex, 0) ; recursive function call Local $return = _ArrayNestedSet($aArray[$i], $vIndex, $vValue) If @error Then Return SetError(@error, @extended + 1, 0) Else Return SetExtended(@extended + 1, 1) EndIf Else $vIndex = $vIndex[0] EndIf EndIf If $vValue = Default Then If $vIndex < 0 Then _ Return SetError(2, $extended) If $vIndex = 0 Then ; delete array and free memory $aArray = 0 Return SetExtended($extended, 1) EndIf If UBound($aArray, 0) = 1 Then ; resize array keeping data ReDim $aArray[$vIndex] Return SetExtended($extended, 1) Else ; create new nested array Local $aTmp[$vIndex] $aArray = $aTmp Return SetExtended($extended, 1) EndIf Else If UBound($aArray) <= $vIndex Then _ Return SetError(2, $extended + 1) ; set value of array entry $aArray[$vIndex] = $vValue Return SetExtended($extended, 1) EndIf EndFunc  
      Examples:
      ; write value to 1st nested array ConsoleWrite("@@ Debug(" & @ScriptLineNumber & ") : write value to 1st nested array" & @CRLF) Local $aTmp1[4] = [1,2,3,4] _ArrayDisplay($aTmp1, "$aTmp1") Local $aArray[2] = [$aTmp1] ConsoleWrite( _ "_ArrayNestedSet($aArray[0], 3, 14) = " & _ArrayNestedSet($aArray[0], 3, 14) & @CRLF & _ " @error = " & @error & @CRLF & _ " @extended = " & @extended & @CRLF & @CRLF) _ArrayDisplay($aArray[0], "$aArray[0]") ; resize 1st nested array ConsoleWrite("@@ Debug(" & @ScriptLineNumber & ") : resize 1st nested array" & @CRLF) ConsoleWrite( _ "_ArrayNestedSet($aArray[0], 8) = " & _ArrayNestedSet($aArray[0], 8) & @CRLF & _ " @error = " & @error & @CRLF & _ " @extended = " & @extended & @CRLF & @CRLF) _ArrayDisplay($aArray[0], "$aArray[0]") ; write array to 1st nested array ConsoleWrite("@@ Debug(" & @ScriptLineNumber & ") : write array to 1st nested array" & @CRLF) Local $aTmp11[4] = [11,12,13,14] _ArrayDisplay($aTmp11, "$aTmp11") ConsoleWrite( _ "_ArrayNestedSet($aArray[0], 2, $aTmp11) = " & _ArrayNestedSet($aArray[0], 2, $aTmp11) & @CRLF & _ " @error = " & @error & @CRLF & _ " @extended = " & @extended & @CRLF & @CRLF) _ArrayDisplay(($aArray[0])[2], "($aArray[0])[2]") ; write value to 2nd nested array using index array ConsoleWrite("@@ Debug(" & @ScriptLineNumber & ") : write value to 2nd nested array using index array" & @CRLF) Local $aIndex1[2] = [2,3] _ArrayDisplay($aIndex1, "$aIndex1") ConsoleWrite( _ "_ArrayNestedSet($aArray[0], $aIndex1, 140) = " & _ArrayNestedSet($aArray[0], $aIndex1, 140) & @CRLF & _ " @error = " & @error & @CRLF & _ " @extended = " & @extended & @CRLF & @CRLF) _ArrayDisplay(($aArray[0])[2], "($aArray[0])[2]") ; resize 2nd nested array ConsoleWrite("@@ Debug(" & @ScriptLineNumber & ") : resize 2nd nested array" & @CRLF) Local $aIndex1[2] = [2,8] _ArrayDisplay($aIndex1, "$aIndex1") ConsoleWrite( _ "_ArrayNestedSet($aArray[0], $aIndex1) = " & _ArrayNestedSet($aArray[0], $aIndex1) & @CRLF & _ " @error = " & @error & @CRLF & _ " @extended = " & @extended & @CRLF & @CRLF) _ArrayDisplay(($aArray[0])[2], "($aArray[0])[2]") ; create new 3rd nested array ConsoleWrite("@@ Debug(" & @ScriptLineNumber & ") : create new 3rd nested array" & @CRLF) Local $aIndex2[3] = [2,7,6] _ArrayDisplay($aIndex2, "$aIndex2") ConsoleWrite( _ "_ArrayNestedSet($aArray[0], $aIndex2) = " & _ArrayNestedSet($aArray[0], $aIndex2) & @CRLF & _ " @error = " & @error & @CRLF & _ " @extended = " & @extended & @CRLF & @CRLF) _ArrayDisplay((($aArray[0])[2])[7], ")($aArray[0])[2])[7]") ; delete 3rd nested array ConsoleWrite("@@ Debug(" & @ScriptLineNumber & ") : delete 3rd nested array" & @CRLF) Local $aIndex3[3] = [2,7,0] _ArrayDisplay($aIndex3, "$aIndex2") ConsoleWrite( _ "_ArrayNestedSet($aArray[0], $aIndex3) = " & _ArrayNestedSet($aArray[0], $aIndex3) & @CRLF & _ " @error = " & @error & @CRLF & _ " @extended = " & @extended & @CRLF) ConsoleWrite("IsArray((($aArray[0])[2])[7]) = " & IsArray((($aArray[0])[2])[7]) & @CRLF & @CRLF) ; write 0 in 1st nested array to delete the 2nd nested array ConsoleWrite("@@ Debug(" & @ScriptLineNumber & ") : write 0 in 1st nested array to delete the 2nd nested array" & @CRLF) Local $aIndex4[1] = [2] _ArrayDisplay($aIndex4, "$aIndex4") ConsoleWrite( _ "_ArrayNestedSet($aArray[0], $aIndex4, 0) = " & _ArrayNestedSet($aArray[0], $aIndex4, 0) & @CRLF & _ " @error = " & @error & @CRLF & _ " @extended = " & @extended & @CRLF) ConsoleWrite("IsArray(($aArray[0])[2]) = " & IsArray(($aArray[0])[2]) & @CRLF & @CRLF) ; delete 1st nested array (same as '$aArray[0] = 0') ConsoleWrite("@@ Debug(" & @ScriptLineNumber & ") : delete 1st nested array (same as '$aArray[0] = 0')" & @CRLF) Local $aIndex5[1] = [0] _ArrayDisplay($aIndex5, "$aIndex5") ConsoleWrite( _ "_ArrayNestedSet($aArray[0], $aIndex5) = " & _ArrayNestedSet($aArray[0], $aIndex5) & @CRLF & _ " @error = " & @error & @CRLF & _ " @extended = " & @extended & @CRLF) ConsoleWrite("IsArray($aArray[0]) = " & IsArray($aArray[0]) & @CRLF & @CRLF)  
×
×
  • Create New...