# String Expression To Integer Array

## Recommended Posts

Hello,
I just needed a small helping function to convert strings like "1, 2, 12-15" to an array [1, 2, 12, 13, 14, 15].
Improvements in speed or functionality are welcome.

```
#include <Array.au3>
Opt("MustDeclareVars", 1)
Global \$sExp1 = "13 - 17, 20, 40, 50 - 60"
Global \$aTest1 = _ExpressionToIntArray(\$sExp1)
_ArrayDisplay(\$aTest1, \$sExp1)

Global \$sExp2 = "3000-3500, 1-20"
Global \$aTest2 = _ExpressionToIntArray(\$sExp2)
_ArrayDisplay(\$aTest2, \$sExp2)

Func _ExpressionToIntArray(\$sExpression)
;funkey 2014.01.16
;check for 'comma'
Local \$aExpression1 = StringSplit(\$sExpression, ",", 2)
Local \$aExpression2[UBound(\$aExpression1)]
;check for 'from x to y'
Local \$iElements = 0, \$aTemp, \$aTemp2
For \$i = 0 To UBound(\$aExpression1) - 1
\$aTemp = StringSplit(\$aExpression1[\$i], "-", 2)
If UBound(\$aTemp) = 2 Then
If \$aTemp[1] - \$aTemp[0] < 0 Then Return SetError(1, 0, 0)
Dim \$aTemp2[\$aTemp[1] - \$aTemp[0] + 1]
For \$j = 0 To UBound(\$aTemp2) - 1
\$aTemp2[\$j] = \$aTemp[0] + \$j
Next
\$iElements += UBound(\$aTemp2)
\$aExpression2[\$i] = \$aTemp2
Else
\$iElements += 1
\$aExpression2[\$i] = \$aTemp
EndIf
Next
;create full array with all elements
Local \$aExpression3[\$iElements]
Local \$k = 0
For \$i = 0 To UBound(\$aExpression1) - 1
For \$j = 0 To UBound(\$aExpression2[\$i]) - 1
\$aTemp = \$aExpression2[\$i]
\$aExpression3[\$k] = Int(\$aTemp[\$j])
\$k += 1
Next
Next
Return \$aExpression3
EndFunc   ;==>_ExpressionToIntArray
```

Greetings from Austria

Programming today is a race between software engineers striving to
build bigger and better idiot-proof programs, and the Universe
trying to produce bigger and better idiots.
So far, the Universe is winning.

##### Share on other sites

Hi funkey

I botched this and it seems a little faster

also it automatically arrange numbers in "range" mask so that if you pass 100 - 10 it will be automatically considered as 10 - 100

(I inverted 17 with 13 in first call for example)

or maybe it would be better generate the list in reverse order? 100 99 98 ......

or maybe you prefer to return an error in that case ?

anyway here it is

```#include <Array.au3>
Opt("MustDeclareVars", 1)
Global \$sExp1 = "17 - 13, 20, 40, 50 - 60"
Local \$time = TimerInit()
Global \$aTest1 = _ExpressionToIntArray(\$sExp1)
ConsoleWrite(TimerDiff(\$time) & @CRLF)
_ArrayDisplay(\$aTest1, \$sExp1)

Global \$sExp2 = "3000-3500, 1-20"
\$time = TimerInit()
Global \$aTest2 = _ExpressionToIntArray(\$sExp2)
ConsoleWrite(TimerDiff(\$time) & @CRLF)
_ArrayDisplay(\$aTest2, \$sExp2)

Func _ExpressionToIntArray(\$sExpression)
Local \$iElements = 0, \$0 = 0, \$1 = 1
Local \$aExpression1 = StringSplit(\$sExpression, ",", 2)
Local \$iElements = 0, \$aTemp[UBound(\$aExpression1)][2], \$aTemp1

For \$x = 0 To UBound(\$aExpression1) - 1
If Not StringInStr(\$aExpression1[\$x], "-") Then \$aExpression1[\$x] &= "-" & \$aExpression1[\$x]
\$aTemp1 = StringSplit(\$aExpression1[\$x], "-", 2)
\$0 = 1 * (Int(\$aTemp1[0]) > Int(\$aTemp1[1]))
\$1 = 1 - \$0
\$aTemp[\$x][0] = Int(\$aTemp1[\$0])
\$aTemp[\$x][1] = Int(\$aTemp1[\$1])
\$iElements += \$aTemp1[\$1] - \$aTemp1[\$0] + 1
Next
Local \$aExpression3[\$iElements], \$k = 0
For \$x = 0 To UBound(\$aExpression1) - 1
For \$y = \$aTemp[\$x][0] To \$aTemp[\$x][1]
; \$aExpression3[\$k] = Int(\$y)
\$aExpression3[\$k] = \$y
\$k += 1
Next
Next
Return \$aExpression3
EndFunc   ;==>_ExpressionToIntArray```

bye

Edited by PincoPanco

small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt....

##### Share on other sites

I cut out a lot of time by using a regexp:

```#include <Array.au3>

\$i1 = TimerInit()
Global \$sExp1 = "13 - 17, 20, 40, 50 - 60"
Global \$aTest1 = _ExpressionToIntArray_new(\$sExp1)
;~ _ArrayDisplay(\$aTest1, \$sExp1)

Global \$sExp2 = "3000-350000, 1-20"
Global \$aTest2 = _ExpressionToIntArray_new(\$sExp2)
;~ _ArrayDisplay(\$aTest2, \$sExp2)
ConsoleWrite(TimerDiff(\$i1) & @CRLF)

\$i2 = TimerInit()
Global \$sExp1 = "13 - 17, 20, 40, 50 - 60"
Global \$aTest1 = _ExpressionToIntArray(\$sExp1)
;~ _ArrayDisplay(\$aTest1, \$sExp1)

Global \$sExp2 = "3000-350000, 1-20"
Global \$aTest2 = _ExpressionToIntArray(\$sExp2)
;~ _ArrayDisplay(\$aTest2, \$sExp2)
ConsoleWrite(TimerDiff(\$i2) & @CRLF)

Func _ExpressionToIntArray(\$sExpression)
;funkey 2014.01.16
;check for 'comma'
Local \$aExpression1 = StringSplit(\$sExpression, ",", 2)
Local \$aExpression2[UBound(\$aExpression1)]
;check for 'from x to y'
Local \$iElements = 0, \$aTemp, \$aTemp2
For \$i = 0 To UBound(\$aExpression1) - 1
\$aTemp = StringSplit(\$aExpression1[\$i], "-", 2)
If UBound(\$aTemp) = 2 Then
If \$aTemp[1] - \$aTemp[0] < 0 Then Return SetError(1, 0, 0)
Dim \$aTemp2[\$aTemp[1] - \$aTemp[0] + 1]
For \$j = 0 To UBound(\$aTemp2) - 1
\$aTemp2[\$j] = \$aTemp[0] + \$j
Next
\$iElements += UBound(\$aTemp2)
\$aExpression2[\$i] = \$aTemp2
Else
\$iElements += 1
\$aExpression2[\$i] = \$aTemp
EndIf
Next
;create full array with all elements
Local \$aExpression3[\$iElements]
Local \$k = 0
For \$i = 0 To UBound(\$aExpression1) - 1
For \$j = 0 To UBound(\$aExpression2[\$i]) - 1
\$aTemp = \$aExpression2[\$i]
\$aExpression3[\$k] = Int(\$aTemp[\$j])
\$k += 1
Next
Next
Return \$aExpression3
EndFunc   ;==>_ExpressionToIntArray

Func _ExpressionToIntArray_new(\$sExpression)
;funkey 2014.01.16
;check for 'comma'
\$aSplit = StringRegExp(\$sExpression,"([^,\s]+)\s*\-\s*([^,\s]+)|([^,\s]+)",4)
\$iUbound = 0
For \$i = 0 To UBound(\$aSplit)-1
; Get ubound of array to create
If UBound(\$aSplit[\$i])=3 Then
\$aTemp = \$aSplit[\$i]
\$iUbound+=Abs(\$aTemp[2]-\$aTemp[1])+1
Else
\$iUbound+=1
EndIf
Next
Local \$aReturn[\$iUbound]
\$iSub = 0
For \$i = 0 To UBound(\$aSplit)-1
; Get ubound of array to create
\$aTemp = \$aSplit[\$i]
If UBound(\$aTemp)=3 Then
For \$j = \$aTemp[1] To \$aTemp[2]
\$aReturn[\$iSub]=\$j
\$iSub+=1
Next
Else
\$aReturn[\$iSub]=\$aTemp[3]
\$iSub+=1
EndIf
Next
Return \$aReturn
EndFunc   ;==>_ExpressionToIntArray```

output:

1091.86530293837
3221.73827203298

added no error handling, so keep that in mind.

Edited by jdelaney

IEbyXPATH-Grab IE DOM objects by XPATH IEscriptRecord-Makings of an IE script recorder ExcelFromXML-Create Excel docs without excel installed GetAllWindowControls-Output all control data on a given window.

##### Share on other sites

the speed improvement is not due to the use of regexp, but on the different management of the arrays

my version do not use regexp, but takes the same time as that of jdelaney

Edited by PincoPanco

small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt....

##### Share on other sites

I wrote this last april, but it was only on the MVP forum.

Not sure how much use it will be to you, it's a little different in purpose and doesn't just work with integers.

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

Local \$aMyRange = _Range_Parse("1-3;5;5-10;9;2-4")

; Result should be: 1-4;5-10
MsgBox(\$MB_OK, "Normalised Range:", _Range_ToString(\$aMyRange))

Func _Range_Parse(\$sRange)
Local \$aRegions = StringSplit(\$sRange, ";"), \$aBounds
Local \$aRet[\$aRegions[0] + 1][2]
\$aRet[0][0] = \$aRegions[0]

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

If StringIsFloat(\$aRegions[\$i]) Or StringIsInt(\$aRegions[\$i]) Then ; Just a single number
\$aRet[\$i][0] = Number(\$aRegions[\$i])
\$aRet[\$i][1] = Number(\$aRegions[\$i])
Else
\$aBounds = StringRegExp(\$aRegions[\$i], "(-?\d+(?:\.\d+)?)\-(-?\d+(?:\.\d+)?)", 3)

If UBound(\$aBounds) <> 2 Then Return SetError(1, 0, 0)

\$aRet[\$i][0] = Number(\$aBounds[0])
\$aRet[\$i][1] = Number(\$aBounds[1])
EndIf
Next

_Range_Normalize(\$aRet)

Return \$aRet
EndFunc   ;==>_Range_Parse

Func _Range_Normalize(ByRef \$aRange)
If Not IsArray(\$aRange) Then Return SetError(1, 0, 0)

; Sort the array by region lower bounds
_ArraySort(\$aRange, 0, 1)

; Check for overlapping regions

Local \$i = 0
While \$i < \$aRange[0][0] - 1
\$i += 1

If \$aRange[\$i][1] >= \$aRange[\$i + 1][0] Then ; Regions Overlap
If \$aRange[\$i + 1][1] > \$aRange[\$i][1] Then \$aRange[\$i][1] = \$aRange[\$i + 1][1]
_ArrayDelete(\$aRange, \$i + 1)
\$aRange[0][0] -= 1
\$i -= 1
EndIf
WEnd

Return 1
EndFunc   ;==>_Range_Normalize

; Could be replaced by a binary search, but \$aRange is expected to contain very few (<10) elements
Func _Range_Contains(ByRef Const \$aRange, \$nNeedle)
If Not IsArray(\$aRange) Then Return SetError(1, 0, 0)

For \$i = 1 To \$aRange[0][0]
If \$nNeedle < \$aRange[\$i][0] Then Return False
If \$nNeedle <= \$aRange[\$i][1] Then Return True
Next

Return False
EndFunc   ;==>_Range_Contains

Func _Range_ToString(ByRef Const \$aRange)
If Not IsArray(\$aRange) Then Return SetError(1, 0, 0)

Local \$sRet = ""

For \$i = 1 To \$aRange[0][0]
If \$aRange[\$i][0] = \$aRange[\$i][1] Then
\$sRet &= \$aRange[\$i][0] & ";"
Else
\$sRet &= \$aRange[\$i][0] & "-" & \$aRange[\$i][1] & ";"
EndIf
Next

\$sRet = StringTrimRight(\$sRet, 1)

Return \$sRet
EndFunc   ;==>_Range_ToString```

##### Share on other sites

Time taken = 352.03113227595 milliseconds which can be compared to the values in jdelaney's post #3.

```#include <Array.au3>

Local \$i1 = TimerInit()

Global \$sExp1 = "13 - 17, 20, 40, 50 - 60"
Global \$aTest1 = StringSplit(Execute('"' & StringRegExpReplace(StringStripWS(\$sExp1, 8), "(\d+)-(\d+)", '" & _Expand(\1, \2) & "') & '"'), ",", 2)

Global \$sExp2 = "3000-350000, 1-20"
Global \$aTest2 = StringSplit(Execute('"' & StringRegExpReplace(StringStripWS(\$sExp2, 8), "(\d+)-(\d+)", '" & _Expand(\1, \2) & "') & '"'), ",", 2)

ConsoleWrite(TimerDiff(\$i1) & @CRLF)
_ArrayDisplay(\$aTest1, \$sExp1)
_ArrayDisplay(\$aTest2, \$sExp2)

Func _Expand(\$a, \$b)
Local \$sRet
For \$i = \$a To \$b
\$sRet &= \$i & ","
Next
Return StringTrimRight(\$sRet, 1)
EndFunc   ;==>_Expand

;Time taken = 352.03113227595 milliseconds```
Edited by Malkey

##### Share on other sites

Thanks for your feedback and improvements. I'll have a look at it. I think reversing the array could be a nice feature and sometimes useful.

Mat: Why isn't the result of your example "1-10" ?

Programming today is a race between software engineers striving to
build bigger and better idiot-proof programs, and the Universe
trying to produce bigger and better idiots.
So far, the Universe is winning.

##### Share on other sites

```Func _ExpressionToIntArray2(\$sExpression)
Local \$aArray = StringRegExp(\$sExpression, '[^\d]*(?|(\d+)[\-\h]+(\d+)|(\d+))', 4)
\$sExpression = ""
For \$i = 0 To UBound(\$aArray) - 1
If UBound(\$aArray[\$i]) > 2 Then
For \$y = (\$aArray[\$i])[1] To (\$aArray[\$i])[2]
\$sExpression &= \$y & ","
Next
Else
\$sExpression &= (\$aArray[\$i])[1] & ","
EndIf
Next
Return StringSplit(StringTrimRight(\$sExpression, 1), ",", 3)
;\$aArray = StringSplit(StringTrimRight(\$sExpression, 1), ",", 3)
;For \$i = 0 To UBound(\$aArray) - 1
;    \$aArray[\$i] = Int(\$aArray[\$i])
;Next
;Return \$aArray
EndFunc   ;==>_ExpressionToIntArray

;; Recommended way, More faster & \$aArray[\$n] = INT (is number, is not strings)
Func _ExpressionToIntArray3(\$sExpression)
Local \$iaArray, \$aExpression = StringRegExp(\$sExpression, '[^\d]*(?|(\d+)\h*\-[\-\h]*(\d+)|(\d+))', 4)
If @Error Then Return SetError(1, 0, 0)
For \$i = 0 To UBound(\$aExpression) - 1
\$iaArray += 1
If UBound(\$aExpression[\$i]) > 2 Then \$iaArray += (\$aExpression[\$i])[2] - (\$aExpression[\$i])[1]
Next
Local \$aArray[\$iaArray]
\$iaArray = 0
For \$i = 0 To UBound(\$aExpression) - 1
If UBound(\$aExpression[\$i]) > 2 Then
For \$y = (\$aExpression[\$i])[1] To (\$aExpression[\$i])[2]
\$aArray[\$iaArray] = \$y
\$iaArray += 1
Next
Else
\$aArray[\$iaArray] = Int((\$aExpression[\$i])[1])
\$iaArray += 1
EndIf
Next
Return \$aArray
EndFunc   ;==>_ExpressionToIntArray```

Ciao.

Edited by DXRW4E

##### Share on other sites

```#include <Array.au3>

\$intarray = _ExpressionToIntArray("13 - 17, 20, 40, 50 - 60")

_ArrayDisplay(\$intarray)

Func _ExpressionToIntArray(\$sExpression)
Local \$aExpression = StringSplit(\$sExpression, ",", 2)

For \$i = 0 To UBound(\$aExpression) -1
\$aExpression[\$i] = Int(Execute(\$aExpression[\$i]))
Next

Return \$aExpression
EndFunc```

Monkey's are, like, natures humans.

##### Share on other sites

Time taken = 352.03113227595 milliseconds which can be compared to the values in jdelaney's post #3.

```#include <Array.au3>

Local \$i1 = TimerInit()

Global \$sExp1 = "13 - 17, 20, 40, 50 - 60"
Global \$aTest1 = StringSplit(Execute('"' & StringRegExpReplace(StringStripWS(\$sExp1, 8), "(\d+)-(\d+)", '" & _Expand(\1, \2) & "') & '"'), ",", 2)

Global \$sExp2 = "3000-350000, 1-20"
Global \$aTest2 = StringSplit(Execute('"' & StringRegExpReplace(StringStripWS(\$sExp2, 8), "(\d+)-(\d+)", '" & _Expand(\1, \2) & "') & '"'), ",", 2)

ConsoleWrite(TimerDiff(\$i1) & @CRLF)
_ArrayDisplay(\$aTest1, \$sExp1)
_ArrayDisplay(\$aTest2, \$sExp2)

Func _Expand(\$a, \$b)
Local \$sRet
For \$i = \$a To \$b
\$sRet &= \$i & ","
Next
Return StringTrimRight(\$sRet, 1)
EndFunc   ;==>_Expand

;Time taken = 352.03113227595 milliseconds```

Your script takes longer than mine on my computer . (it's an old one)....yours took mine 1331.39271715158

You would have to run ALL options relative to your computer.

Still a cool technique though

Edit: 1 run is hardly a good sample, I'd collect the times for 20 runs to have a good one

Edited by jdelaney

IEbyXPATH-Grab IE DOM objects by XPATH IEscriptRecord-Makings of an IE script recorder ExcelFromXML-Create Excel docs without excel installed GetAllWindowControls-Output all control data on a given window.

##### Share on other sites

Thanks for your feedback and improvements. I'll have a look at it. I think reversing the array could be a nice feature and sometimes useful.

Mat: Why isn't the result of your example "1-10" ?

Because it was written to work with numbers other than integers. 4.5 is in between 4 and 5 so you can't combine those regions.

As I said, it was written with rather a different purpose in mind I suspect.

##### Share on other sites

Duh! I thought 12 - 15 was a calculation.

Monkey's are, like, natures humans.

##### Share on other sites

```#include <Array.au3>

\$timer = TimerInit()
\$intarray = _ExpressionToIntArray("13 - 17, 20, 40, 50 - 60")
ConsoleWrite(TimerDiff(\$timer) & @LF)
_ArrayDisplay(\$intarray)

Func _ExpressionToIntArray(\$sExpression)
\$sExpression = StringStripWS(\$sExpression, 8)
Local \$aExpression = StringSplit(\$sExpression, ",", 2)
Local \$sArray = ""
For \$i = 0 To UBound(\$aExpression) - 1
If StringInStr(\$aExpression[\$i], "-") Then
\$sArray &= _ParseElement(\$aExpression[\$i])
Else
\$sArray &= \$aExpression[\$i] & "|"
EndIf

Next
\$sArray = StringTrimRight(\$sArray, 1)
Return StringSplit(\$sArray, "|", 2)
EndFunc   ;==>_ExpressionToIntArray

Func _ParseElement(\$val)
Local \$stmp = ""
Local \$atmp = StringSplit(\$val, "-", 2)
For \$i = Int(\$atmp[0]) To Int(\$atmp[1])
\$stmp &= \$i & "|"
Next
Return \$stmp
EndFunc   ;==>_ParseElement```

Edited by JohnOne

Monkey's are, like, natures humans.

##### Share on other sites

```#include <Array.au3>

GLobal COnst \$string = "13 - 17, 20, 40, 50 - 60"

Global COnst \$int_array = StringRegExp(\$string, "\d+", 3)

_ArrayDisplay(\$int_array)```

##### Share on other sites
```#include <Array.au3>

GLobal COnst \$string = "13 - 17, 20, 40, 50 - 60"

Global COnst \$int_array = StringRegExp(\$string, "\d+", 3)

_ArrayDisplay(\$int_array)```

That won't return 14 through 16, or 51 through 59 in the array.

Edited by jdelaney

IEbyXPATH-Grab IE DOM objects by XPATH IEscriptRecord-Makings of an IE script recorder ExcelFromXML-Create Excel docs without excel installed GetAllWindowControls-Output all control data on a given window.

##### Share on other sites

oops, misunderstood (didn't read) the requirements.  TIme for bed just about.  ::heh::

• 1

##### Share on other sites

was curious to make some statistics

used this call to test time spent by various functions:

```\$timer = TimerInit()
\$intarray = _ExpressionToIntArray("13 - 17, 20, 40, 50 - 60, 3000-3500, 1-2000")
ConsoleWrite(TimerDiff(\$timer) & @LF)```

results:

function   run 1      run 2      run 3      run 4      run 5      run 6     average
-------------------------------------------------------------------------------------
funkey     43.539891, 38.180830, 40.049224, 44.582481, 37.371509, 56.409403 43.355556
-------------------------------------------------------------------------------------
PincoPanco 16.368002, 13.228496, 13.647544, 13.994236, 15.770998, 11.503137 14.085402
-------------------------------------------------------------------------------------
jdelaney   16.732852, 13.349741, 11.991188, 17.148268, 14.528103, 13.387735 14.522981
-------------------------------------------------------------------------------------
Malkey     18.182757, 17.414224, 16.700446, 15.997843, 18.562415, 17.123684 17.330228
-------------------------------------------------------------------------------------
DXRW4E
function2  16.287265, 19.737983, 18.706008, 17.454732, 15.404751, 16.382529 17.328878
function3  13.876065, 16.734529, 13.158096, 11.551188, 18.626948, 16.785652 15.122080
-------------------------------------------------------------------------------------
JohnOne    25.481450, 23.892422, 18.949056, 17.244091, 17.856180, 20.220447 20.607274

(results truncated to 6 decimals to fit in table)

small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt....

##### Share on other sites

I can shave a bit off the time of mine.

```#include <Array.au3>

\$timer = TimerInit()
\$intarray = _ExpressionToIntArray("13 - 17, 20, 40, 50 - 60, 3000-3500, 1-2000")
ConsoleWrite(TimerDiff(\$timer) & @LF)

Func _ExpressionToIntArray(\$sExpression)
\$sExpression = StringStripWS(\$sExpression, 8)
Local \$aExpression = StringSplit(\$sExpression, ",", 2)
Local \$sArray = ""
For \$i = 0 To UBound(\$aExpression) - 1
If StringInStr(\$aExpression[\$i], "-") Then
_ParseElement(\$sArray, \$aExpression[\$i])
Else
\$sArray &= \$aExpression[\$i] & "|"
EndIf

Next
\$sArray = StringTrimRight(\$sArray, 1)
Return StringSplit(\$sArray, "|", 2)
EndFunc   ;==>_ExpressionToIntArray

Func _ParseElement(ByRef \$stmp, \$val)
Local \$atmp = StringSplit(\$val, "-", 2)
For \$i = Int(\$atmp[0]) To Int(\$atmp[1])
\$stmp &= \$i & "|"
Next
Return \$stmp
EndFunc   ;==>_ParseElement```

Monkey's are, like, natures humans.

##### Share on other sites

I can shave a bit off the time of mine.

JohnOne

before shave    25.481450, 23.892422, 18.949056, 17.244091, 17.856180, 20.220447 20.607274

after shave     29.538949, 17.359468, 19.136789, 22.047774, 18.002008, 19.673170 20.959693

small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt....

##### Share on other sites

I think a lot more needs to be added to the inital string, to get execution time-lengths up to seconds.

Millisecs are fleeting

IEbyXPATH-Grab IE DOM objects by XPATH IEscriptRecord-Makings of an IE script recorder ExcelFromXML-Create Excel docs without excel installed GetAllWindowControls-Output all control data on a given window.

## Create an account

Register a new account

×

• Wiki

• Back

• Git