You can use this custom proc that uses a function for replace:
set a "1 abc 2 abc 3 abc 4 abc......... 100 abc"
proc rangeSub {a first last string sub} {
# This variable keeps the count of matches
set count 0
proc re_sub {str first last rep} {
upvar count count
incr count
# If match number within wanted range, replace with rep, else return original string
if {$count >= $first && $count <= $last} {
return $rep
} else {
return $str
}
}
set cmd {[re_sub "\0" $first $last $sub]}
set b [subst [regsub -all "\\y$string\\y" $a $cmd]]
return $b
}
# Here replacing the 1st to 3rd occurrences of abc
puts [rangeSub $a 1 3 "abc" "bcd"]
# => 1 bcd 2 bcd 3 bcd 4 abc......... 100 abc
puts [rangeSub $a 2 3 "abc" "bcd"]
# => 1 abc 2 bcd 3 bcd 4 abc......... 100 abc
Change the call to rangeSub $a 1 50 "abc" "bcd"
to replace the first 50 occurrences.
codepad demo
Alternative using indices and string range
:
set a "1 abc 2 abc 3 abc 4 abc......... 100 abc"
proc rangeSub {a first last string sub} {
set idx [regexp -all -inline -indices "\\yabc\\y" $a]
set start [lindex $idx $first-1 0]
set end [lindex $idx $last-1 1]
regsub -all -- "\\yabc\\y" [string range $a $start $end] bcd result
return [string range $a 0 $start-1]$result[string range $a $end+1 end]
}
puts [rangeSub $a 1 3 abc bcd]