Warm tip: This article is reproduced from serverfault.com, please click

Meaning of "whole" in this TCL foreach loop (regex)

发布于 2020-12-06 02:21:36

I am trying to understand what the "whole" keyword does in the foreach loop below. I wrote a regex expression to find numbers between a | and ) in a text. See the output below when I run the following script.

#!/usr/bin/expect

set text "A(1|1) B(1|3) C(1|6)"

#regex to find numbers between | and )
set pattern {\|([0-9]+)\)}  
                         
set matches [regexp -all -inline $pattern $text]

foreach {whole num} $matches {
        puts $num
}

puts "---"

foreach num $matches {
        puts $num
}

Output:

1
3
6
---
|1)
1
|3)
3
|6)
6

The first loop output is desired, but why is the second loop showing |1),|3), when I remove the "whole" keyword?

Questioner
TheEyesHaveIt
Viewed
0
community wiki 2020-12-06 17:16:04

As you've been told, regexp -all -inline produces a list of things it has matched, where that list has several entries per match (first is the full match, subsequent entries are per capturing subexpression); its actual result here is |1) 1 |3) 3 |6) 6. What's going on with the foreach with the whole?

Well, the word whole is not special at all. It's just a variable name. The general form of that type of foreach is:

foreach listOfVariableNames listToIterateOver body

The {whole num} is a list of two variable names, so each iteration through $matches we pull off two elements of the list and assign them to each of the variables. If the body had instead been:

puts "whole = '$whole' num = '$num'"

The output would have been:

whole = '|1)' num = '1'
whole = '|3)' num = '3'
whole = '|6)' num = '6'

As you're actually not otherwise using whole, the effect is to ignore the whole-matches and just use the sub-expression matches. This is a fairly common pattern.