# Stringregexp problem on binary string

## Recommended Posts

Hi

I am trying to split a binary string into an array based on a certain length

Is stringregexp compatible with binary strings?

Below doesn't seem to work (not all code here as I get the bitmap into a (binary) string \$BMP2Data)

\$splitMeOn = '.{1,' & \$BMP2LineWidth - \$padBytes2 & '}' also no difference

```;Get all of the picturelines of 2nd bitmap in a seperate array
ReDim \$picLines[\$BMP2Height]
;~  \$picLines=stringregexp(\$BMP2Data,"(.{" & \$BMP2LineWidth - \$padBytes2 & "})*",1)
\$splitMeOn = '(.{1,' & \$BMP2LineWidth - \$padBytes2 & '})*'
\$picLines=stringregexp(\$BMP2Data, \$splitMeOn, 3)
consolewrite(@error &  \$splitMeOn & " array " & ubound(\$picLines) & ";" & stringlen(\$bmp2data) &  ";" & \$BMP2Height & @crlf)```

I rewrote it by calculating myself but thats not very efficient (not fast enough for me)

```for \$i=0 to \$BMP2Height-1
\$picLines[\$i]=StringMid(\$BMP2Data, 1 + (\$i * \$BMP2LineWidth), (\$BMP2LineWidth - \$padBytes2))
next```

Base sample thats working to prove the concept

```\$array = StringRegExp('0123456', '(.{1,2})', 3)
for \$i = 0 to UBound(\$array) - 1
msgbox(0, "RegExp Test with Option 2 - " & \$i, \$array[\$i])
Next```
Edited by junkew

##### Share on other sites

The quantifier "*" is called to matches the entire pattern zero or more times.

```#include <Array.au3>

Local \$sString = "1234#5678"
Local \$avMatch = StringRegExp(\$sString, "(\d)*", 3) ; Can match even nothing to success
If IsArray(\$avMatch) Then _ArrayDisplay(\$avMatch, "(\d)*")

\$avMatch = StringRegExp(\$sString, "\d*", 3) ; Can match even nothing to success, alternative, but implicitly anchored
If IsArray(\$avMatch) Then _ArrayDisplay(\$avMatch, "\d*")

\$avMatch = StringRegExp(\$sString, "(\d)+", 3) ; Must match at least once to success
If IsArray(\$avMatch) Then _ArrayDisplay(\$avMatch, "(\d)+")

\$avMatch = StringRegExp(\$sString, "\d+", 3) ; Must match at least once to success, not anchored
If IsArray(\$avMatch) Then _ArrayDisplay(\$avMatch, "\d+")

\$avMatch = StringRegExp(\$sString, "(\d+)", 3) ; The intended way
If IsArray(\$avMatch) Then _ArrayDisplay(\$avMatch, "(\d+)")

\$avMatch = StringRegExp(\$sString, "\G(\d+)", 3) ; Don't skip characters, match only at the start of the last match
If IsArray(\$avMatch) Then _ArrayDisplay(\$avMatch, "\G(\d+)")```

Test a few cases before you try the big toys.

##### Share on other sites

As said before its not working when I use

\$splitMeOn = '.{1,' & \$BMP2LineWidth - \$padBytes2 & '}'

\$splitmeOn has the value .{1,288} which should describe any character from 1-288 characters

\$splitMeOn = '(.{1,' & \$BMP2LineWidth - \$padBytes2 & '})'

doesn't do the trick either

Edited by junkew

##### Share on other sites

And the data is what? Is it a string representation of the image data? Binary representation?

##### Share on other sites

Simplified and made a full example.

Its binary data so I assume stringregexp is not working on binarydata?

```#include <IE.au3>
#include <Array.au3>
#include <string.au3>

Local \$sString = _hextostring(\$hexString)

consolewrite("Total length <" & stringlen(\$sString) & ">" &@crlf)

;~ tryit("(.{0,288})*")
;~ tryit(".{0,288}*")
;~ tryit("(.{0,288})+")
tryit(".{0,288}+")
;~ tryit("(.{0,288}+)")
;~ tryit("\G({0,288}+)")
tryit(".{0,20}+")
func tryIt(\$p)
Local \$avMatch = StringRegExp(\$sString, \$p, 3)
If IsArray(\$avMatch) Then
_ArrayDisplay(\$avMatch, \$p)
for \$i=0 to ubound(\$avMatch)-1
consolewrite(stringlen(\$avmatch[\$i]) & @crlf)
next
else
consolewrite(\$p & " has not returned an array" & @crlf)
EndIf

EndFunc
Exit```

##### Share on other sites

most likely it seems stringregexp stops at encountering 00 at position 302 in the string

Is this expected behavior?

288:CD 289:DF 290:E3 291:D0 292:E1 293:E6 294:A7 295:95 296:79 297:83 298:56 299:24 300:74 301:3C 302:00 303:74 304:3C 305:00 306:74 307:3C 308:00 309:74 310:3C 311:00 312:74 313:3C 314:00 315:74 316:3C

```tryit(".{0,288}+")
;~ tryit("(.{0,288}+)")
;~ tryit("\G({0,288}+)")
;~ tryit(".{0,20}+")

for \$i=288 to (288 * 2 + 38)
consolewrite( \$i & ":" & stringmid(\$hexString,\$i*2+1,2) & " ")
Next```

##### Share on other sites

Yes, the binary representation of it is the literal string "00" but turning it into a character produces a null terminated string, I guess:

```#include <Array.au3>
#include <string.au3>

Local \$sString = _HexToString(\$hexString)

ConsoleWrite("Total length <" & StringLen(\$sString) & ">" & @CRLF)

;~ tryit("(.{0,288})*")
;~ tryit(".{0,288}*")
;~ tryit("(.{0,288})+")
tryit(".{0,288}+", \$hexString)
;~ tryit("(.{0,288}+)")
;~ tryit("\G({0,288}+)")
tryit(".{0,20}+", \$sString)

Func tryIt(\$p, \$sStr)
Local \$avMatch = StringRegExp(\$sStr, \$p, 3)
If IsArray(\$avMatch) Then
_ArrayDisplay(\$avMatch, \$p)
For \$i = 0 To UBound(\$avMatch) - 1
ConsoleWrite(StringLen(\$avMatch[\$i]) & @CRLF)
Next
Else
ConsoleWrite(\$p & " has not returned an array" & @CRLF)
EndIf

EndFunc   ;==>tryIt
Exit```

##### Share on other sites

from Authenticity in an other thread in this forum...(i was able to use it very well, thx)

```\$sData = StringTrimRight(StringRegExpReplace(StringTrimLeft(\$xBytes, 2), "(.{" & \$iStride & "})", "\1@"), 1)
\$avData = StringSplit(\$sData, "@")```

Example:

```#include <Array.au3>
#include <GDIPlusConstants.au3>
#include <WinAPI.au3>
#include <GDIPlus.au3>
;"\pic2.jpg"
;"\testfullscreen.bmp"
\$t = TimerInit()
\$array=_GetPixelRowsFromBMP(@ScriptDir & "\pic2.jpg", @ScriptDir & "\Test.txt");writes the rows into a textfile
\$m = TimerDiff(\$t)
ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : time = ' & \$m & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console

Func _GetPixelRowsFromBMP(\$sImage, \$sOutputFile)  ;thx to
Local \$hImage, \$hBmp, \$iW, \$iH
Local \$tBD, \$iWidth, \$iHeight, \$iStride, \$iFmt
Local \$pData, \$tPixels, \$xBytes
Local \$avPixels, \$hFile

\$hFile = FileOpen(\$sOutputFile, 2)
If @error Then Return SetError(1, 1, 0)

_GDIPlus_Startup()

If @error Then Return SetError(1, 2, 0)

\$iW = _GDIPlus_ImageGetWidth(\$hImage)
\$iH = _GDIPlus_ImageGetHeight(\$hImage)
\$hBmp = _GDIPlus_BitmapCloneArea(\$hImage, 0, 0, \$iW, \$iH, \$GDIP_PXF32ARGB)
\$tBD = _GDIPlus_BitmapLockBits(\$hBmp, 0, 0, \$iW, \$iH, BitOR(\$GDIP_ILMREAD, \$GDIP_ILMWRITE), \$GDIP_PXF32ARGB)

\$iWidth = DllStructGetData(\$tBD, 1)
\$iHeight = DllStructGetData(\$tBD, 2)
\$iStride = DllStructGetData(\$tBD, 3)
\$iFmt = DllStructGetData(\$tBD, 4)
\$pData = DllStructGetData(\$tBD, 5)

\$tPixels = DllStructCreate("byte[" & \$iW * \$iH * 4 & "]", \$pData)
\$xBytes = DllStructGetData(\$tPixels, 1)

\$sData = StringTrimRight(StringRegExpReplace(StringTrimLeft(\$xBytes, 2), "(.{" & \$iStride & "})", "\1@"), 1)
\$avData = StringSplit(\$sData, "@")

For \$i = 1 To \$avData[0]
FileWrite(\$hFile, \$avData[\$i] & @CRLF)
Next
FileClose(\$hFile)

_GDIPlus_BitmapUnlockBits(\$hBmp, \$tBD)
_WinAPI_DeleteObject(\$hBmp)
_GDIPlus_ImageDispose(\$hImage)
_GDIPlus_Shutdown()
return \$avData
EndFunc   ;==>_GetImagePixels```

##### Share on other sites

That example is exactly breaking around 00 character at position 302. So that link will not solve the problem I have

What i am trying to do is indeed to break up a picture into several lines (which works when I do put it in an array myself).

It just doesn't work with the stringregexp

```local \$hexString = "D4E6E9CDDFE3C9DCE1C9DBE0C9DBE0C9DBE0C9DBE0C9DBE0C9DBE0C9DBE0C9DBE0C9DBE0C9DBE0C9DBE0C9DBE0C9DBE0C9DBE0C9DBE0C9DBE0C9DBE0C9DBE0C9DBE0C9DBE0C9DBE0C9DBE0C9DBE0C9DBE0C9DBE0C9DBE0C9DBE0C9DBE0C9DBE0C9DBE0C9DBE0C9DBE0C9DBE0C9DBE0C9DBE0C9DBE0C9DBE0C9DBE0C9DBE0C9DBE0C9DBE0C9DBE0C9DBE0C9DBE0C9DBE0C2D6DBC2D6DBC2D6DBC2D6DBC2D6DBC2D6DBC2D6DBC2D6DBC2D6DBC2D6DBC2D6DBC2D6DBC2D6DBC2D6DBC2D6DBC2D6DBC2D6DBC2D6DBC2D6DBC2D6DBC2D6DBC2D6DBC2D6DBC2D6DBC2D6DBC2D6DBC2D6DBC2D6DBC2D6DBC2D6DBC2D6DBC2D6DBC2D6DBC2D6DBC2D6DBC2D6DBC2D6DBC2D6DBC2D6DBC2D6DBC2D6DBC9DBE0C9DBE0C9DBE0C9DCE1CBDDE2CDDFE3D4E6E9CDDFE3D0E1E6A79579835624743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C00743C007D4C159F8766D2E4E8D1E4E7CBDDE2A79579A27D55DDCFC0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE8DFD5A27D55A8957AD4E6E9CBDDE2835624DCCEBFFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFDFEFEDBCEBF835624D9EAECC9DCE1743C00FCFDFDFCFDFDFCFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFBFCFCFAFBFBF2F4F6743C00DEECEFCBDDE2743C00FAFAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF9FAFAF8FAFAF2F4F5EAEEF0743C00E0EDF00D0A"
Local \$sString = _hextostring(\$hexString)

consolewrite("Total length <" & stringlen(\$sString) & ">" &@crlf)

\$sString=StringTrimRight(StringRegExpReplace(StringTrimLeft(\$sString, 2), "(.{" & 288 & "})", "\1@"), 1)

consolewrite("Total length <" & stringlen(\$sString) & ">" &@crlf)```

##### Share on other sites

Is there any reason the data needs be a character string of the hex values? You can't match a string that contain a null character because it's denoting the end of the string, unless you walk the string using a byte buffer or something similar. From the example above, you already got the data in binary minus the "0x" at the start of the string, capture the binary string using a multiply of 2 characters, representing one byte.

##### Share on other sites

That example is exactly breaking around 00 character at position 302

Sry, you did a mistake in your script...

If you split the \$hexstring first and after that convert every part of the splitted hexstring into a binary, then you have what you are looking for!

```#include <Array.au3>
#include <String.au3>

ConsoleWrite("Total length <" & StringLen(\$hexString) / 2 & ">" & @CRLF) ;number in bytes....right?

\$hexString = StringTrimRight(StringRegExpReplace(\$hexString, "(.{" & 288 * 2 & "})", "\1@"), 1) ;2 character in a hex is one byte, regex places a @ at every 288. "byte"
\$array = StringSplit(\$hexString, "@") ;splits the hex"string" into an array  , every single "string" has a lenght of 288 bytes (288 * 2 hex-character)
_ArrayDisplay(\$array) ;you could convert every "row" to a string with _hextostring

\$sString = ""
For \$i = 1 To UBound(\$array) - 1 ;now we convert the hex to binary and put all together into a big string
\$sString &= _HexToString(\$array[\$i]) ;make every (288 byte) part of the hexstring to a real string including nullbytes!
ConsoleWrite(@CRLF & StringLen(_HexToString(\$array[\$i])) & "      " & _HexToString(\$array[\$i]) & @CRLF) ; this function doesn´t SHOW anything after a nullbyte, but the string is not cutted by the function! it really exists with full lenght
Next

ConsoleWrite(@CRLF & "Total length <" & StringLen(\$sString) & ">" & @CRLF) ;this is the lenght of the whole string
ConsoleWrite(@CRLF & \$sString) ;shows you not the 1730 bytes.....because after the first nullbyte ...you know it ;)
ConsoleWrite(@CRLF)

;or so...
\$string=_hextostring(\$hexstring)  ;into binary
dim \$row[stringlen(\$string)/288+2]  ;number of rows of the bitmap
\$k=0
for \$i=1 to stringlen(\$string) step 288 ;we step through the string....
\$k+=1  ;nice construction, isn´t it?   :o)
\$row[\$k]=stringmid(\$string,\$i,288) ;...and write every string with the lenght of 288 byte into an array
next

;ok, lets compare what we have done in the 2 examples
if \$row[3]=_HexToString(\$array[3]) then MsgBox(0, 'Compare', "...match" )```
Edited by AndyG

##### Share on other sites

The hexstring is only there to make the sample reproducible in a short amount of code.

I have a binary string (based on the bitmap bits) where I want to do a split with the stringregexp function.

This function seems to be breaking on 00 bytes (most likely a \0 string terminator)

For me it doesn't make sense to first convert the binary to hex (is slow) and then split and finally convert back to the binaryrepresentation.

Then I will stick to the mid(string,start,end) splitting myself.

##### Share on other sites

Based on the sample a full example that shows that stringregexp is not able to handle the 00 (method 2)

And the one with stringregexprepl combined with a split seems to be a workaround (method 1) although I have some doubt on what happens if I have the binary value of @ in my bitmap

stringregexp and stringregexprepl seems to behave differently on matching

calculator.bmp should be placed in %temp% folder

Tried with many regular expressions but results stay the same

From the demo this line should be correct

\$avData=stringregexp(\$xBytes, ".{1," & \$iStride & "}+", 3)

```#include <Array.au3>
#include <GDIPlusConstants.au3>
#include <WinAPI.au3>
#include <GDIPlus.au3>

\$fileName=@tempdir & "\calculator.bmp"

\$t = TimerInit()
\$array=_GetPixelRowsFromBMP(\$filename, @Tempdir & "\Test.txt",1);writes the rows into a textfile
\$array=_GetPixelRowsFromBMP(\$filename, @Tempdir & "\Test2.txt",2);writes the rows into a textfile

\$m = TimerDiff(\$t)
ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : time = ' & \$m & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console

Func _GetPixelRowsFromBMP(\$sImage, \$sOutputFile, \$method)  ;thx to
Local \$hImage, \$hBmp, \$iW, \$iH
Local \$tBD, \$iWidth, \$iHeight, \$iStride, \$iFmt
Local \$pData, \$tPixels, \$xBytes
Local \$avPixels, \$hFile

_GDIPlus_Startup()

If @error Then Return SetError(1, 2, 0)

\$iW = _GDIPlus_ImageGetWidth(\$hImage)
\$iH = _GDIPlus_ImageGetHeight(\$hImage)
\$hBmp = _GDIPlus_BitmapCloneArea(\$hImage, 0, 0, \$iW, \$iH, \$GDIP_PXF32ARGB)
\$tBD = _GDIPlus_BitmapLockBits(\$hBmp, 0, 0, \$iW, \$iH, BitOR(\$GDIP_ILMREAD, \$GDIP_ILMWRITE), \$GDIP_PXF32ARGB)

\$iWidth = DllStructGetData(\$tBD, 1)
\$iHeight = DllStructGetData(\$tBD, 2)
\$iStride = DllStructGetData(\$tBD, 3)
\$iFmt = DllStructGetData(\$tBD, 4)
\$pData = DllStructGetData(\$tBD, 5)

\$tPixels = DllStructCreate("byte[" & \$iW * \$iH * 4 & "]", \$pData)
\$xBytes = DllStructGetData(\$tPixels, 1)

if \$method=1 Then
;~ Method 1 by replacing and splitting
\$sData = StringTrimRight(StringRegExpReplace(StringTrimLeft(\$xBytes, 2), "(.{" & \$iStride & "})", "\1@"), 1)
\$avData = StringSplit(\$sData, "@")

\$hFile = FileOpen(\$sOutputFile, 2)
If @error Then Return SetError(1, 1, 0)

For \$i = 1 To \$avData[0]
FileWrite(\$hFile, \$avData[\$i] & @CRLF)
Next

FileClose(\$hFile)
EndIf

if \$method=2 Then
;~ Method 2 by replacing and returning array directly
;~  \$sData = StringTrimRight(StringRegExpReplace(StringTrimLeft(\$xBytes, 2), "(.{" & \$iStride & "})", "\1@"), 1)
;~     \$avData = StringSplit(\$sData, "@")
\$avData=stringregexp(\$xBytes, ".{1," & \$iStride & "}+", 3)

\$hFile = FileOpen(\$sOutputFile, 2)
If @error Then Return SetError(1, 1, 0)

For \$i = 1 To \$avData[0]
FileWrite(\$hFile, \$avData[\$i] & @CRLF)
Next

FileClose(\$hFile)
EndIf

_GDIPlus_BitmapUnlockBits(\$hBmp, \$tBD)
_WinAPI_DeleteObject(\$hBmp)
_GDIPlus_ImageDispose(\$hImage)
_GDIPlus_Shutdown()
return \$avData
EndFunc   ;==>_GetImagePixels

Exit```

CALCULATOR.bmp

##### Share on other sites

```If \$method = 2 Then

\$avData = StringRegExp(\$xBytes, ".{1," & \$iStride & "}+", 3)

\$hFile = FileOpen(\$sOutputFile, 2)
If @error Then Return SetError(1, 1, 0)

For \$i = 1 To \$avData[0]
FileWrite(\$hFile, \$avData[\$i] & @CRLF)
Next

FileClose(\$hFile)
EndIf```

For \$i = 1 To \$avData[0]

Wrong.

## Create an account

Register a new account