1

I have the following code:

set a "10.20.30.40"
regsub -all {.([0-9]+).([0-9]+).} $a {\2 \1} b

I am trying to grep 2nd and 3rd octet of the IP address.

Expected output:

20 30

Actual output:

20 04 0

What is my mistake here?

Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
Bharathi
  • 63
  • 7
  • You need to escape "." character like "\." . Without escaping, "." matches any character. – Min Naing Oo May 19 '15 at 08:51
  • tried the same , but no luck regsub -all {\.([0-9]+)\.([0-9]+)\.} $a {\2 \1} b – Bharathi May 19 '15 at 08:53
  • @Bharathi : Sorry. Your intention is not clear to me. Do you need to match the `20.30.` in the variable `a` and replace it with some other ? – Dinesh May 19 '15 at 09:10
  • Got it. You need replace ".20.30" with "30.20". Right ? – Dinesh May 19 '15 at 09:14
  • 1
    @Bharathi : If you simply want to save the 2nd and 3rd octet, then why `regsub` at all ? `regexp` itself is enough, Right ? Why bother back-reference also ? – Dinesh May 19 '15 at 09:19
  • This is one of the situations where regex is not a suitable tool. You should `split` instead of trying to do that... `[split $a .]` gives you `{10 20 30 40}` which you can easily then use `lrange` to get the second and third elements together... – Jerry May 19 '15 at 10:57

2 Answers2

2

I'd stay away from regular expressions altogether:

set b [join [lrange [split $a .] 1 2]]

Split the value on dots, take the 2nd and 3nd elements, and join them with a space.

glenn jackman
  • 238,783
  • 38
  • 220
  • 352
1

You need to set the variables for the match and captured groups, then you can access them. Here is an example:

set a "10.20.30.40"
set rest [regexp {[0-9]+\.([0-9]+)\.([0-9]+)\.[0-9]+} $a match submatch1 submatch2]
puts $submatch1
puts $submatch2

Output of the demo

20
30

EDIT:

You can use regsub and backerferences this way (I am now replacing the 3rd and 2nd octets, just for demonstration). Note that a literal dot must be escaped:

set a "10.20.30.40"
regsub -all {\.([0-9]+)\.([0-9]+)\.} $a {.\2.\1.} b
puts $b

Output of the demo:

10.30.20.40

To obtain a "20 30" string, you need to use

regsub -all {^[0-9]+\.([0-9]+)\.([0-9]+)\.[0-9]+$} $a {\1 \2} b
Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
  • Thanks for your effort, but i want to grep those octets using regsub and back reference. ... as mentioned in my question , regesub command is available . but it is not working – Bharathi May 19 '15 at 08:59
  • Thanks :) .... it is working fine.. Could you please let me know any docs to understand about back reference – Bharathi May 19 '15 at 09:20
  • Sure, the best IMO is [Regular-expressions.info](http://www.regular-expressions.info/backref.html). – Wiktor Stribiżew May 19 '15 at 09:22
  • i have one more question , could you please help me out. set a "1 abc 2 abc 3 abc 4 abc 5 abc 6 abc 7 abcd" . i want replace first 3 "abc" as bhu usinf regsub and back reference ... please help me on this.. – Bharathi May 21 '15 at 08:54
  • Here you are: `set a "1 abc 2 abc 3 abc 4 abc 5 abc 6 abc 7 abcd" \\NEWLINE regsub {([0-9]+\s+)abc( +[0-9]+ +)abc( +[0-9]+ +)abc(.*)} $a {\1bhu\2bhu\3bhu\4} b \\NEWLINE puts $b`. Instead of `\\NEWLINE`, use a real newline. – Wiktor Stribiżew May 21 '15 at 09:56
  • Hi thanks, here whether can we use bound quantifiers or anything for following scenrio, because consider variable a have "1 abc 2 abc ......100 abc" in that i want to match first 50 abc matches.... then our regsub will be very lengthy..... we need to avoid this .... any idea ??? – Bharathi May 22 '15 at 05:59