Jump to content
Sign in to follow this  
xoraxax

How to parse range

Recommended Posts

xoraxax

Hello.

I have a string like this (for example a range of pages to print):

5,9,10-15

I need to know if the user input is in that range or not. How can script it?

 

Share this post


Link to post
Share on other sites
Blue_Drache

Usually you send that to a text box, so look at ControlSend()


Lofting the cyberwinds on teknoleather wings, I am...The Blue Drache

Share this post


Link to post
Share on other sites
xoraxax

Hm. I mean a different thing

For example

We have a form:

Range: __InputRange___

Value: __inputValue___

 

User input: inputRange="5,9,10-15", Value=7

And i need to evaluate that 7 is not in the range "5,9,10-15". But 12 (for example) is in that range.

So i need to parse the range string to array or something and check if Value is in that array or not.

Share this post


Link to post
Share on other sites
JustSomeone

I believe you need to take a look at stringregexp / stringsplit and some weird combination of them both, hoever i never actually understood those two ;)

Share this post


Link to post
Share on other sites
Melba23

xoraxax,

This is a function that I developed to parse positive ranges:

#include <MsgBoxConstants.au3>

$sRet = _Expand_Range("5-7,9,10-15", ",")

MsgBox($MB_SYSTEMMODAL, "Expanded", $sRet)


Func _Expand_Range($vRange, $sDelim = ";")

    Local $iNumber, $aSplit_2
    If $sDelim = Default Then $sDelim = ";"
    $vRange = StringStripWS($vRange, 8)
    $aSplit_1 = StringSplit($vRange, $sDelim)
    $vRange = ""
    For $i = 1 To $aSplit_1[0]
        ; Check for correct range syntax
        If Not StringRegExp($aSplit_1[$i], "^\d+(-\d+)?$") Then Return SetError(3, 0, -1)
        $aSplit_2 = StringSplit($aSplit_1[$i], "-")
        Switch $aSplit_2[0]
            Case 1
                $vRange &= $aSplit_2[1] & $sDelim
            Case 2
                If Number($aSplit_2[2]) >= Number($aSplit_2[1]) Then
                    $iNumber = $aSplit_2[1] - 1
                    Do
                        $iNumber += 1
                        $vRange &= $iNumber & $sDelim
                    Until $iNumber = $aSplit_2[2]
                EndIf
        EndSwitch
    Next

    Return StringTrimRight($vRange, 1)
EndFunc   ;==>_Expand_Range
I hope it is useful. :)

M23

Edited by Melba23
Typo

Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind._______My UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Share this post


Link to post
Share on other sites
xoraxax

Too late. I've solved it already. 

Anyway Thank you =)

Share this post


Link to post
Share on other sites
xoraxax

Here is my Func, in case someone want it. 

func isInRange($range,$value)
dim $trunk[29]
for $t In $trunk
    $t=0
next

$range_sp=StringSplit($range,",")
for $i=1 to $range_sp[0]
    if StringInStr($range_sp[$i],"-")=0 Then
        $trunk[$range_sp[$i]]=1
    Else
        $r_sp=StringSplit($range_sp[$i],"-")
        if $r_sp[0]<>2 then
            MsgBox(0,0,"Неверно указан диапазон")
            Exit
        EndIf
        if int($r_sp[1])>int($r_sp[2]) Then
            MsgBox(0,0,"Неверно указан диапазон")
            Exit
        EndIf
        for $ii=$r_sp[1] to $r_sp[2]
            $trunk[$ii]=1
        Next
    EndIf
Next
if $trunk[int($value)]=1 then
        return 1
    Else
        return 0
    EndIf
EndFunc

Share this post


Link to post
Share on other sites
Chimp

you are building an array with as many elements as the full range and then set to 1 only the elements of the array corresponding with values in your range.
then you check if an array element contains 0 or 1 to see if that number is within your range.

... seems a not much optimized way

I suggest to have a look to> this function by Mat

in this case could be used in this way:

(modified separator from ";" to ",")

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

Local $aMyRange = _Range_Parse("5,9,10-15") ; your ranges
Local $Value = 4 ; value to check if is inside

MsgBox(0, "in range?", _Range_Contains($aMyRange, $Value) & @CRLF)


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

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

Share this post


Link to post
Share on other sites
xoraxax

Thank you. Array was the first thing i thought about. It is interesting to discover another way to work it out. Though it won't be more than 28 elements so i think it is ok in my case.

Share this post


Link to post
Share on other sites
AZJIO

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

$Res = _Belongs("5,9,4-15,6, 22-88,1", '6')
MsgBox(0, '@error = ' & @error, 'Belongs? = ' & $Res)
; MsgBox(0, "in range?", $f)

Func _Belongs($sRange, $sNum)
    $sRange = StringStripWS($sRange & ',', 8) ; Удаляем все пробелы
    ; $sRange = StringRegExpReplace($sRange, '[^\d,-]', '')
    If StringRegExp($sRange, '[^\d,-]') Or StringRegExp($sRange, '[,-]{2,}') Then Return SetError(2, 0, -2) ; вылет с ошибкой если существуют иные символы

    ; флаг=1, используется смещение для пошагового поиска всех элементов
    $iOffset = 1
    $iStart = 1
    $iEnd = 1
    While 1
        $aRes = StringRegExp($sRange, '[,-]', 1, $iOffset)
        If @error Then ExitLoop ; Выход из цикла если более не найдено
        $iOffset = @extended ; Сохраняет позицию, от которой начать следующий поиск
        $iStart = $iEnd
        $iEnd = $iOffset
        Switch $aRes[0]
            Case ','
                ; MsgBox(0, 'Сообщение', StringMid($sRange, $iStart, $iEnd-$iStart-1))
                If StringMid($sRange, $iStart, $iEnd - $iStart - 1) = $sNum Then Return SetError(0, 0, 1)
            Case '-'
                $sNum1 = Number(StringMid($sRange, $iStart, $iEnd - $iStart - 1))
                ; MsgBox(0, 'sNum1', $sNum1)
                $aRes = StringRegExp($sRange, '[,-]', 1, $iOffset)
                If @error Then ExitLoop
                $iOffset = @extended ; Сохраняет позицию, от которой начать следующий поиск
                If $aRes[0] = '-' Then Return SetError(3, 0, -3) ; вылет с ошибкой если повтор интерпретации диапазона
                $iStart = $iEnd
                $iEnd = $iOffset
                $sNum2 = Number(StringMid($sRange, $iStart, $iEnd - $iStart - 1))
                ; MsgBox(0, 'sNum2', $sNum2)
                ; If $sNum < $sNum1 Or $sNum > $sNum2 Then
                If $sNum >= $sNum1 And $sNum <= $sNum2 Then Return SetError(0, 0, 1)
        EndSwitch
    WEnd

    Return SetError(0, 0, 0)
EndFunc   ;==>_Belongs

Share this post


Link to post
Share on other sites
Iczer

$sRange = "1,3,5-8,12-18,22,25"
$dValue = 7

$q = Inside2($sRange, $dValue)
ConsoleWrite($q&@CRLF)

Func Inside2($sRange, $dValue)
    Local $aRange, $i

    $aRange = StringSplit($sRange,";,")
    For $i = 1 To $aRange[0]
        $aRangeP = StringRegExp($aRange[$i],"(\d+)",3)
        Switch UBound($aRangeP)
            Case 1
                If $dValue = Number($aRangeP[0]) Then Return True
            Case 2
                If Number($aRangeP[1]) > $dValue And $dValue > Number($aRangeP[0]) Then Return True
        EndSwitch
    Next
    Return False
EndFunc

Share this post


Link to post
Share on other sites
Malkey

Local $value = 7 ; 12 ;
Local $range = "5,9,10-15,17"

Local $Res = _IsInRange($range, $value)
MsgBox(0, 'Result', 'Belongs? = ' & $Res)


Func _IsInRange($iRange, $iValue)
    Local $iRange2 = Execute("'" & StringRegExpReplace(StringStripWS($iRange, 8), "(\d+)-(\d+)", "'& __Expand($1,$2) & '") & "'")
    ;ConsoleWrite($iRange2 & @LF)
    Return StringRegExp($iRange2, "(^|,)" & $iValue & "(,|$)") ; If $iValue matches any values in $iRange2, then returns 1, else returns 0.
EndFunc   ;==>_IsInRange

;Internal function.
Func __Expand($Start, $End)
    Local $sRet
    For $i = $Start To $End
        $sRet &= $i & ","
    Next
    Return StringTrimRight($sRet, 1)
EndFunc   ;==>__Expand

Share this post


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
Sign in to follow this  

×