Что нового

[RegExp] Проверка корректности вводимых в Input чисел месяца и их диапазонов

n-deer

Новичок
Сообщения
16
Репутация
0
Добрый день.

Есть форма, где пользователь должен ввести числа месяца или их диапазоны, разделенные запятыми (наподобии того, как указываются страницы при печати документов из различных программ). Т.е. что-то вроде "1, 5, 16-18, 0" ("0" подразумевает последний день месяца). Захотелось сделать проверку вводимого в Input текста "на лету". Посмотрев примеры на оф форуме, написал такой вот скрипт:

Код:
#include <GUIConstants.au3>

Global $iTimer = -1
Global $iTime_Expired = 1000
Global $sText, $sTextPrev

GUICreate("", 320 ,120)
$hInput = GUICtrlCreateInput( "", 10,  20, 300, 20)
GUISetState(@SW_SHOW)

While 1
	$msg = GUIGetMsg()
	If $msg = $GUI_EVENT_CLOSE Then Exit

	If $iTimer <> -1 And TimerDiff($iTimer) >= $iTime_Expired Then
		$iTimer = -1
		GUICtrlSetBkColor($hInput, 0xFFFFFF)
	EndIf

	$sText = GuiCtrlRead($hInput)
	If $sTextPrev <> $sText Then
		$iTimer = -1
		GUICtrlSetBkColor($hInput, 0xFFFFFF)
	EndIf

	If StringRegExp($sText, '[^\d\s,-]') Then
		GUICtrlSetData($hInput, StringRegExpReplace($sText, '[^\d\s,-]', ""))
		$iTimer = TimerInit()
		GUICtrlSetBkColor($hInput, 0xFFCACA)
	Endif
	$sTextPrev = GUICtrlRead($hInput)
Wend


Но он проверяет лишь то, что вводимый символ входит в разрешенный набор, не проверяя их последовательность, в результате чего он пропустит такие строки как:

1256, 45, 000
-, 5, 16-18, 0
,,,,, 0
-,-,-,-,-,----

и т.п. Хотелось бы сделать проверку более интеллектуальной. Проблема в том, что с регулярными выражениями практически не знаком. Весь день читал различные мануалы, смотрел примеры, но так и не смог написать ничего работающего.

Сам алгоритм проверки видится таким:
Первый символ: [0-3]
После "0" могут идти: [,\s]
После "1" и "2" могут идти: [,\s\d-]
После "3" могут идти: [,\s01-]
После "\s" могут идти: [0-3,-]
После "," могут идти: [0-3\s]
После "-" могут идти: [1-3\s]
После двух подряд цифр могут идти: [,\s-]

Помогите, пожалуйста, перевести этот алгоритм в регулярное выражение. Или может быть посоветуете какие-то альтернативные способы реализовать такую проверку.
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Как то так:

Код:
#include <GuiConstants.au3>
#include <WindowsConstants.au3>
#include <EditConstants.au3>

Global $sLast_Data

GUICreate("Input Changed GUI", 300, 140)

GUICtrlCreateLabel("Restrict type: [Day of month (including ranges)]:", 20, 40)
$Input = GUICtrlCreateInput("", 20, 70, 260, 20)

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

GUISetState()
GUIRegisterMsg($WM_COMMAND, "WM_COMMAND")

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

Func WM_COMMAND($hWnd, $nMsg, $wParam, $lParam)
	Local $nNotifyCode = BitShift($wParam, 16)
	Local $nID = BitAND($wParam, 0xFFFF)
	Local $hCtrl = $lParam
	
	Switch $nID
		Case $Input
			Switch $nNotifyCode
				Case $EN_UPDATE
					__ResetColor()
					
					If Not StringRegExp(GUICtrlRead($Input), "^(,?([0-2][0-9]?|3[0-1]?)(,?|-))*(?!=3[0-1]?)$") Then
						GUICtrlSetBkColor($Input, 0xFFCACA)
						AdlibRegister("__ResetColor", 3000)
						
						;Comment next line to remove the "Beep Sound" on wrong set of characters
						DllCall("User32.dll", "int", "MessageBeep", "int", -1)
						
						GUICtrlSetData($Input, $sLast_Data)
					Else
						$sLast_Data = GUICtrlRead($Input)
					EndIf
				Case $EN_SETFOCUS, $EN_KILLFOCUS
					__ResetColor()
			EndSwitch
	EndSwitch
	
	Return $GUI_RUNDEFMSG
EndFunc

Func __ResetColor()
	AdlibUnRegister("__ResetColor")
	GUICtrlSetBkColor($Input, 0xFFFFFF)
EndFunc
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
madmasles [?]
1, 2 и 3 вводятся без ограничения.
И это не единственный недостаток. Нужно дорабатывать выражение, завтра на свежую голову попробую доделать, и заодно выложу библиотеку для установки ограничений в Input-элементах :sleeping:
 
Автор
N

n-deer

Новичок
Сообщения
16
Репутация
0
Угу, пропускает числа любой длины, если они состоят из [1-3], например: "111112222233333". Плюс не дает вставлять пробелы.

CreatoR
и заодно выложу библиотеку для установки ограничений в Input-элементах
Спасибо! :smile:
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Вообщем вот доработал выражение:

Код:
'^(((?<![3-9])[0-9]|(?<=3)[0-1]){1,2}(?!\d)[,\s-]*)*$'

тут запятые, пробелы и дефисы, могут присутствовать в любом количестве, если нужно ограничить чем то одним, тогда наверное так:
Код:
'^(((?<![3-9])[0-9]|(?<=3)[0-1]){1,2}(?!\d)(, ?|-)?)*$'
 
Автор
N

n-deer

Новичок
Сообщения
16
Репутация
0
CreatoR
Спасибо! Пытаюсь вникнуть в выражение ;)
 

Redline

AutoIT Гуру
Сообщения
506
Репутация
375
Если интересует способ без регэкспов, то вот:
Код:
#include <Date.au3>
_DateIsValid($sDate)
 
Верх