1

i am trying to write a regexp which will check whether the ip is valid or not.Facing issue when i give 256 as value it is still matching 2, and reg will store the value as 1 since the pattern is matched.

set ip "256.256.255.1"
set reg [regexp -all{^([1-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]).([1-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]).([1-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]).([1-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])} $ip match ] 
puts $reg
Cœur
  • 37,241
  • 25
  • 195
  • 267
Prince Dhadwal
  • 255
  • 3
  • 7
  • 1
    I wouldn't recommend using regular expression for this case. Using regular expression will actually reduce performance. Check out https://stackoverflow.com/questions/15587213/regex-for-a-number-greater-than-x-and-less-than-y – Tejus Jul 26 '17 at 06:38

2 Answers2

0

The unescaped . will match any character, not just a . symbol. The capturing groups are unnecessary since you are only interested in 1 whole match. Besides, no need to use -all since you want to validate a single string.

Use

set text {256.256.255.1}
set pattern {^(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])){3}$} 
regexp $pattern $text match
if {[info exists match]} {
    puts $match
} else {
    puts "No match"
}

See the online Tcl demo.

Pattern details:

  • ^ - start of string
  • (?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]) - first octet matching numbers from 0 to 255
  • (?:\.(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])){3} - 3 occurrences of a . (see \.) and the octet subpattern
  • $ - end of string.
Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
  • Thanks. It is working. Could you please elaborate more how (?:) and {3} will work in the above mentioned solution. – Prince Dhadwal Jul 26 '17 at 09:34
  • These have already been explained. See [*What is a non-capturing group? What does a question mark followed by a colon (?:) mean?*](https://stackoverflow.com/questions/3512471) and information on [**limiting quantifiers**](http://www.regular-expressions.info/repeat.html#limit). Also, see my former answer to [*use case for `?:` in tcl regexp*](https://stackoverflow.com/questions/38438851/use-case-for-in-tcl-regexp/38453664#38453664). – Wiktor Stribiżew Jul 26 '17 at 09:39
0

For very complicated regexes, breaking it into pieces help readability:

set octet {(?:[1-9]?[0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])}
set ip_re [format {\m%s\.%s\.%s\.%s\M} {*}[lrepeat 4 $octet]]

Note, your regex will not match octets 10 to 99 or 0.

testing

set str "hello 1.2.3.4 there 127.0.0.1 friend 256.9.99.999 x255.255.255.255"
regexp -all $ip_re $str               ;# => 2
regexp -all -inline $ip_re $str       ;# => 1.2.3.4 127.0.0.1
glenn jackman
  • 238,783
  • 38
  • 220
  • 352