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?
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.