Jump to content

StringRegExp problems


ttleser
 Share

Recommended Posts

I've got a GUI input box and I need it to tell me when I'm inputting anything other than...

A. Only Numbers (ex. 0340384)

or

B. Numbers with a single period with more numbers (3434.9834) or (.049) or (438.9)

I'm basically looking for have the input box act just like it were a calculator input (only numbers and one decimal point), though my new script isn't for a calculator.

I'm using MrCreators script >> http://www.autoitscript.com/forum/index.ph...OnlyNumbers.au3 and I've tried modifying the script many ways, I can get it to do only numbers and a single period, but if a 2nd period is typed it erases the 1st..

Here's MrCreator's script:

#include-once
#include <GuiConstants.au3>

If Not IsDeclared("WM_COMMAND")         Then Global Const $WM_COMMAND       = 0x0111
If Not IsDeclared("WM_MOVE")            Then Global Const $WM_MOVE          = 0x0003
If Not IsDeclared("WM_LBUTTONDOWN")     Then Global Const $WM_LBUTTONDOWN   = 0x0201
If Not IsDeclared("WM_RBUTTONDOWN")     Then Global Const $WM_RBUTTONDOWN   = 0x0204

Global $sToolTip_Text[2] = ["You can only type a number or period here", "Unacceptable Character:"]
Global $sInputs_Array[1]

GUIRegisterMsg($WM_COMMAND,     "MY_WM_COMMAND")
GUIRegisterMsg($WM_MOVE,        "WM_CLEAR_TOOLTIP")
GUIRegisterMsg($WM_LBUTTONDOWN, "WM_CLEAR_TOOLTIP")
GUIRegisterMsg($WM_RBUTTONDOWN, "WM_CLEAR_TOOLTIP")

; $CtrlId must be an ID value, -1 can not be used!
Func _GuiInputSetOnlyNumbers($CtrlId)
    Local $iUbound = UBound($sInputs_Array)
    ReDim $sInputs_Array[$iUbound+1]
    $sInputs_Array[$iUbound] = $CtrlId
EndFunc

Func _Input_Changed($hWnd, $CtrlId)
    ToolTip("")
    Local $Read_Input = GUICtrlRead($CtrlId)
    If StringRegExp($Read_Input, '[^0-9][^.]{0,1}') Then
        GUICtrlSetData($CtrlId, StringRegExpReplace($Read_Input, '[^0-9][^\.]', ''))
        
        Local $Gui_Get_Pos = WinGetPos($hWnd)
        Local $Ctrl_Get_Pos = ControlGetPos($hWnd, "", $CtrlId)
        
        Local Const $SM_CYCAPTION = 4;Titelbar heigth
        Local Const $SM_CXFIXEDFRAME = 7;Window border size
        
        Local $X_Pos = $Gui_Get_Pos[0] + $Ctrl_Get_Pos[0] + $Ctrl_Get_Pos[2] + GetSystemMetrics($SM_CXFIXEDFRAME)
        Local $Y_Pos = $Gui_Get_Pos[1] + $Ctrl_Get_Pos[1] + $Ctrl_Get_Pos[3] + GetSystemMetrics($SM_CYCAPTION)
        
        ToolTip($sToolTip_Text[0], $X_Pos, $Y_Pos, $sToolTip_Text[1], 3, 1+4)
        DllCall("user32.dll", "int", "MessageBeep", "int", 0x0)
    EndIf
EndFunc

Func WM_CLEAR_TOOLTIP($hWnd, $iMsg, $wParam, $lParam)
    ToolTip("")
    Return $GUI_RUNDEFMSG
EndFunc

Func MY_WM_COMMAND($hWnd, $iMsg, $wParam, $lParam)
    If $hWnd = 0 Or Not WinExists($hWnd) Then Return $GUI_RUNDEFMSG
    
    Local $nNotifyCode = BitShift($wParam, 16)
    Local $nID = BitAND($wParam, 0xFFFF)
    Local Const $EN_CHANGE = 0x300
    Local Const $EN_UPDATE = 0x400
    Local Const $EN_SETFOCUS = 0x100
    Local Const $EN_KILLFOCUS = 0x200
    
    For $i = 1 To UBound($sInputs_Array)-1
        If $nID = $sInputs_Array[$i] Then
            Switch $nNotifyCode
                Case $EN_UPDATE;$EN_CHANGE
                    _Input_Changed($hWnd, $sInputs_Array[$i])
                Case $EN_SETFOCUS, $EN_KILLFOCUS
                    ToolTip("")
            EndSwitch
            ExitLoop
        EndIf
    Next
    
    Return $GUI_RUNDEFMSG
EndFunc

Func GetSystemMetrics($Flag)
    Local $iRet = DllCall('user32.dll', 'int', 'GetSystemMetrics', 'int', $Flag)
    Return $iRet[0]
EndFunc

And here's the testing code

#include <GuiConstants.au3>
#include <GUIInputSetOnlyNumbers.au3>

$GUI = GUICreate("_GUIInputSetOnlyNumbers() Demo", 400, 100)

$Input_1 = GUICtrlCreateInput("", 20, 10, 360, 20)
_GuiInputSetOnlyNumbers($Input_1)

$Input_2 = GUICtrlCreateInput("", 20, 40, 360, 20)
_GuiInputSetOnlyNumbers($Input_2)


$Exit = GUICtrlCreateButton("Exit", 20, 70, 60, 20)

GUISetState()

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE, $Exit
            ExitLoop
    EndSwitch
WEnd

I'm thinking the problem is with these lines...

If StringRegExp($Read_Input, '[^0-9][^.]{0,1}') Then
        GUICtrlSetData($CtrlId, StringRegExpReplace($Read_Input, '[^0-9][^\.]', ''))
Link to comment
Share on other sites

"([\d]*\.?[\d]+)|([\d+])"

EDIT: Not tested but this probably works too

"([\d]*\.?[\d]+)"

Edited by GEOSoft

George

Question about decompiling code? Read the decompiling FAQ and don't bother posting the question in the forums.

Be sure to read and follow the forum rules. -AKA the AutoIt Reading and Comprehension Skills test.***

The PCRE (Regular Expression) ToolKit for AutoIT - (Updated Oct 20, 2011 ver:3.0.1.13) - Please update your current version before filing any bug reports. The installer now includes both 32 and 64 bit versions. No change in version number.

Visit my Blog .. currently not active but it will soon be resplendent with news and views. Also please remove any links you may have to my website. it is soon to be closed and replaced with something else.

"Old age and treachery will always overcome youth and skill!"

Link to comment
Share on other sites

Thanks for the reply, but that didn't work. Anything I type in the box immediately gives me the message saying I've typed something that it doesn't like. ^_^

Here's what I changed:

If StringRegExp($Read_Input, "([\d]*\.?[\d]+)|([\d+])") Then

GUICtrlSetData($CtrlId, StringRegExpReplace($Read_Input, '[^0-9][^\.]', ''))

Link to comment
Share on other sites

  • Moderators

Global $s_data = ".399.049.3939testing3990.888"

$s_data = _Give_Me_Only_Digits_And_One_Decimal($s_data)
ConsoleWrite($s_data & @CRLF)


Func _Give_Me_Only_Digits_And_One_Decimal($s_data)
    If StringRegExp($s_data, "(?:\..*?\.|(?!\.)\D)") = 0 Then Return $s_data
    
    Local $a_sre = StringRegExp($s_data, "^\d*\.", 1)
    If Not @error Then
        Return StringRegExpReplace($s_data, "^(" & $a_sre[0] & ")|(?:(\D+)|(\d+))", "\1\3")
    EndIf
    
    Return StringRegExpReplace($s_data, "(\d+)|(\D+)", "\1")
EndFunc

Edit:

Actually, this would probably be just fine:

Func _Give_Me_Only_Digits_And_One_Decimal($s_data)
    If StringRegExp($s_data, "(?:\..*?\.|(?!\.)\D)") = 0 Then Return $s_data
    Return StringRegExpReplace($s_data, "^(\d*\.\d*)|(?:(\D+)|(\d+))", "\1\3")
EndFunc
Edited by SmOke_N

Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.

Link to comment
Share on other sites

If SmOke_N's example works, use his.

Here is another.

;
#include <GuiConstants.au3>

If Not IsDeclared("WM_COMMAND") Then Global Const $WM_COMMAND = 0x0111
If Not IsDeclared("WM_MOVE") Then Global Const $WM_MOVE = 0x0003
If Not IsDeclared("WM_LBUTTONDOWN") Then Global Const $WM_LBUTTONDOWN = 0x0201
If Not IsDeclared("WM_RBUTTONDOWN") Then Global Const $WM_RBUTTONDOWN = 0x0204

Global $sToolTip_Text[2] = ["You can only type a number or period here", "Unacceptable Character:"]
Global $sInputs_Array[1], $flag = 0

GUIRegisterMsg($WM_COMMAND, "MY_WM_COMMAND")
GUIRegisterMsg($WM_MOVE, "WM_CLEAR_TOOLTIP")
GUIRegisterMsg($WM_LBUTTONDOWN, "WM_CLEAR_TOOLTIP")
GUIRegisterMsg($WM_RBUTTONDOWN, "WM_CLEAR_TOOLTIP")
$GUI = GUICreate("_GUIInputSetOnlyNumbers() Demo", 400, 100)

$Input_1 = GUICtrlCreateInput("", 20, 10, 360, 20)
_GuiInputSetOnlyNumbers($Input_1)

$Input_2 = GUICtrlCreateInput("", 20, 40, 360, 20)
_GuiInputSetOnlyNumbers($Input_2)

$Exit = GUICtrlCreateButton("Exit", 20, 70, 60, 20)

GUISetState()

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE, $Exit
            ExitLoop
    EndSwitch
WEnd

; $CtrlId must be an ID value, -1 can not be used!
Func _GuiInputSetOnlyNumbers($CtrlId)
    Local $iUbound = UBound($sInputs_Array)
    ReDim $sInputs_Array[$iUbound + 1]
    $sInputs_Array[$iUbound] = $CtrlId
EndFunc  ;==>_GuiInputSetOnlyNumbers

Func _Input_Changed($hWnd, $CtrlId)
    ToolTip("")
    Local $Read_Input = GUICtrlRead($CtrlId)

    StringReplace($Read_Input, ".", ".")
    Local $Num = @extended; Number of decimal points present
    If $Num > 1 Then $flag = 1; Stops 2 decimal points

    If $Num = 1 Then; one decimal point is present
        Local $aAns = StringSplit($Read_Input, ".")
        Local $iAns1 = StringLen($aAns[1]); Number of digits before decimal point.
        Local $iAns2 = StringLen($aAns[2]); Number of digits after decimal point.

    ;(3434.9834) or (.049) or (438.9) <-- Prevent these numbers occurring
        If ($iAns1 = 4 And $iAns2 > 4) Or ($iAns1 = "" And $iAns2 > 3) Or ($iAns1 = 3 And $iAns2 > 1) Then $flag = 1
    EndIf

    If StringRegExp($Read_Input, '[^0-9\.][^.]{0,1}') Or $flag = 1 Then
        GUICtrlSetData($CtrlId, StringTrimRight($Read_Input, 1)); Remove last character entered.
    ;GUICtrlSetData($CtrlId, StringRegExpReplace($Read_Input, '[^0-9\.][^\.]', ''))
        Local $Gui_Get_Pos = WinGetPos($hWnd)
        Local $Ctrl_Get_Pos = ControlGetPos($hWnd, "", $CtrlId)

        Local Const $SM_CYCAPTION = 4;Titelbar heigth
        Local Const $SM_CXFIXEDFRAME = 7;Window border size

        $X_Pos = $Gui_Get_Pos[0] + $Ctrl_Get_Pos[0] + $Ctrl_Get_Pos[2] + GetSystemMetrics($SM_CXFIXEDFRAME)
        $Y_Pos = $Gui_Get_Pos[1] + $Ctrl_Get_Pos[1] + $Ctrl_Get_Pos[3] + GetSystemMetrics($SM_CYCAPTION)

        ToolTip($sToolTip_Text[0], $X_Pos, $Y_Pos, $sToolTip_Text[1], 3, 1 + 4)
        DllCall("user32.dll", "int", "MessageBeep", "int", 0x0)
        $flag = 0
    EndIf

EndFunc  ;==>_Input_Changed

Func WM_CLEAR_TOOLTIP($hWnd, $iMsg, $wParam, $lParam)
    ToolTip("")
    Return $GUI_RUNDEFMSG
EndFunc  ;==>WM_CLEAR_TOOLTIP

Func MY_WM_COMMAND($hWnd, $iMsg, $wParam, $lParam)
    If $hWnd = 0 Or Not WinExists($hWnd) Then Return $GUI_RUNDEFMSG

    Local $nNotifyCode = BitShift($wParam, 16)
    Local $nID = BitAND($wParam, 0xFFFF)
    Local Const $EN_CHANGE = 0x300
    Local Const $EN_UPDATE = 0x400
    Local Const $EN_SETFOCUS = 0x100
    Local Const $EN_KILLFOCUS = 0x200

    For $i = 1 To UBound($sInputs_Array) - 1
        If $nID = $sInputs_Array[$i] Then
            Switch $nNotifyCode
                Case $EN_UPDATE;$EN_CHANGE
                    _Input_Changed($hWnd, $sInputs_Array[$i])
                Case $EN_SETFOCUS, $EN_KILLFOCUS
                    ToolTip("")
            EndSwitch
            ExitLoop
        EndIf
    Next

    Return $GUI_RUNDEFMSG
EndFunc  ;==>MY_WM_COMMAND

Func GetSystemMetrics($flag)
    Local $iRet = DllCall('user32.dll', 'int', 'GetSystemMetrics', 'int', $flag)
    Return $iRet[0]
EndFunc  ;==>GetSystemMetrics
;

About line #56, you can add more conditional expressions to the "If" statement to produce a fail on input if required.

Link to comment
Share on other sites

Is there something wrong with the simple approach?

Local $Read_Input = GUICtrlRead($CtrlId)
;; Add code for multiple decimal points here.
If NOT StringRegExp(StringRight($Read_Input, 1), "\.|\d") Then
    $Read_Input = StringTrimRight($Read_Input, 1)
    GUICtrlSetData($CtrlId, $Read_Input)
EndIf

George

Question about decompiling code? Read the decompiling FAQ and don't bother posting the question in the forums.

Be sure to read and follow the forum rules. -AKA the AutoIt Reading and Comprehension Skills test.***

The PCRE (Regular Expression) ToolKit for AutoIT - (Updated Oct 20, 2011 ver:3.0.1.13) - Please update your current version before filing any bug reports. The installer now includes both 32 and 64 bit versions. No change in version number.

Visit my Blog .. currently not active but it will soon be resplendent with news and views. Also please remove any links you may have to my website. it is soon to be closed and replaced with something else.

"Old age and treachery will always overcome youth and skill!"

Link to comment
Share on other sites

Thanks all that replied, but I used Malkey's code as his allowed the same type of reaction like I was looking for where it would have the tooltip pop up if something wrong was typed...

@Malkey - LOL. I tested it and found that it would error if I had entered a value with more than 3 digits to the right of the decimal point... What I posted was an example of what I was looking for.. I removed the IF statement and it functions exactly like what I needed.

;(3434.9834) or (.049) or (438.9) <-- Prevent these numbers occurring

If ($iAns1 = 4 And $iAns2 > 4) Or ($iAns1 = "" And $iAns2 > 3) Or ($iAns1 = 3 And $iAns2 > 1) Then $flag = 1

Question though. What would I need to do to restrict the value to only greater than a .05? Doesn't matter what's on the left side of the decimal point, but the right can only be .05 or greater.. .01, .001 wouldn't work, but .05, .06 or greater would. My program needs to restrict the input to only 2 digits on the right side of the decimal point but it can't be less than .05.

Is it possible to have 2 tooltips come up depending on the issue? If I tried to type period twice or a non-number it would have the normal saying of "You can only type a number or period here", but if you tried to type a value less than .05, it would say ".05 is the maximum value on the right of the decimal point" (or something like that).

Thanks much!

Link to comment
Share on other sites

If Number($sStr) < .05 Then ....Do whatever

George

Question about decompiling code? Read the decompiling FAQ and don't bother posting the question in the forums.

Be sure to read and follow the forum rules. -AKA the AutoIt Reading and Comprehension Skills test.***

The PCRE (Regular Expression) ToolKit for AutoIT - (Updated Oct 20, 2011 ver:3.0.1.13) - Please update your current version before filing any bug reports. The installer now includes both 32 and 64 bit versions. No change in version number.

Visit my Blog .. currently not active but it will soon be resplendent with news and views. Also please remove any links you may have to my website. it is soon to be closed and replaced with something else.

"Old age and treachery will always overcome youth and skill!"

Link to comment
Share on other sites

  • Moderators

Thanks all that replied, but I used Malkey's code as his allowed the same type of reaction like I was looking for where it would have the tooltip pop up if something wrong was typed...

Kind of silly really. The first line of the function code I provided could have been modded to your needs without error.

Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.

Link to comment
Share on other sites

@GeoSoft - I don't think that'll work. What if it were 3.03 or 13.04? Would it still "Do whatever" in those instances?

I want the script to say "Look, I don't care what numbers are on the left of the period, but what's on the right of the period better not be less than .05"

Link to comment
Share on other sites

Actually, I figured something out. I added some more code, might be clunky but it works.

Add 2 more IF statements to the _Input_Changed function.

If (StringInStr($Read_Input,".") <> 0 AND StringMid($Read_Input,(StringInStr($Read_Input,".")+1),1) = 0 AND StringMid($Read_Input,(StringInStr($Read_Input,".")+2),1) < 5 AND $iAns2 >= 2) Then $flag = 2

AND

If StringRegExp($Read_Input, '[^0-9\.][^.]{0,1}') OR $flag = 2 Then
        GUICtrlSetData($CtrlId, StringTrimRight($Read_Input, 1)); Remove last character entered.
   ;GUICtrlSetData($CtrlId, StringRegExpReplace($Read_Input, '[^0-9\.][^\.]', ''))
        Local $Gui_Get_Pos = WinGetPos($hWnd)
        Local $Ctrl_Get_Pos = ControlGetPos($hWnd, "", $CtrlId)

        Local Const $SM_CYCAPTION = 4;Titelbar heigth
        Local Const $SM_CXFIXEDFRAME = 7;Window border size

        $X_Pos = $Gui_Get_Pos[0] + $Ctrl_Get_Pos[0] + $Ctrl_Get_Pos[2] + GetSystemMetrics($SM_CXFIXEDFRAME)
        $Y_Pos = $Gui_Get_Pos[1] + $Ctrl_Get_Pos[1] + $Ctrl_Get_Pos[3] + GetSystemMetrics($SM_CYCAPTION)
        
        ToolTip(".05 is the minimum value", $X_Pos, $Y_Pos, $sToolTip_Text[1], 3, 1 + 4)
        DllCall("user32.dll", "int", "MessageBeep", "int", 0x0)
        $flag = 0
        
EndIf
Link to comment
Share on other sites

Sorry I didn't get back sooner. I thought any number larger than .05 was okay. To do what you want I should have posted

If Number(StringMid($sStr, StringInStr($sStr, "."))) < .05 Then ....Do whatever

Edited by GEOSoft

George

Question about decompiling code? Read the decompiling FAQ and don't bother posting the question in the forums.

Be sure to read and follow the forum rules. -AKA the AutoIt Reading and Comprehension Skills test.***

The PCRE (Regular Expression) ToolKit for AutoIT - (Updated Oct 20, 2011 ver:3.0.1.13) - Please update your current version before filing any bug reports. The installer now includes both 32 and 64 bit versions. No change in version number.

Visit my Blog .. currently not active but it will soon be resplendent with news and views. Also please remove any links you may have to my website. it is soon to be closed and replaced with something else.

"Old age and treachery will always overcome youth and skill!"

Link to comment
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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...