Myjab
Myjab

Reputation: 944

Parse all matches in a string in tcl

I have a string as follows

set temp "
temp   : value
temp1  : value1
tempvalue
abc    = 23:445:726
abcdef = 456::985
abcdef = 123:45:7
abcdef = 098:45:56:8
"

In this I want an output in which the values after "=" should be set to one variable. Output should be

"456::985 123:45:7 098:45:56:8".

I used

set result [regexp "abcdef\\s*=\\s*(\\S*)" $temp match v1]

but not able to get all

I have got the answer using regexp with -inline -all and -line, to store the result in list and then traverse through it to get the values. I need a one liner

set result [regexp -inline -all -line "abcdef\\s*=\\s*(\\S*)" $temp]

Output is

{abcdef = 456::985} 456::985 {abcdef = 123:45:7} 123:45:7 {abcdef = 098:45:56:8} 098:45:56:8

Then traverse through this to set them all in one string. But i want to know if there is any easy way to do this. Thanks in advance.

Upvotes: 0

Views: 136

Answers (3)

glenn jackman
glenn jackman

Reputation: 247182

Since you're using line-oriented matching, take advantage of the line anchor:

% regexp -inline -all -line {\S+$} $temp
456::985 123:45:7 098:45:56:8

So, to save the values as a string:

set values [join [regexp -inline -all -line {\S+$} $temp]]

If there may not be whitespace after the equal, use the pattern {[^=\s]+$}

My whole answer assumes there's only going to be one equal sign per line.


Responding to the updated sample input:

foreach {m word} [regexp -inline -all -line {=\s*(\S+)$} $temp] {
    lappend words $word
}
puts [join $words]
23:445:726 456::985 123:45:7 098:45:56:8

Upvotes: 0

Hai Vu
Hai Vu

Reputation: 40773

Here is another approach: think of each line as 3 tokens: key, equal sign, and value:

set result {}
foreach {key eq_sign value} $temp { lappend result $value }

This approach is simple to understand, but it will not work if the value contains spaces.

Upvotes: 0

patthoyts
patthoyts

Reputation: 33223

Given this example you don't need regexp. Split the lines into pieces and create a new list.

set r {}
foreach line [split $temp \n] {
    if {[string trim $line] eq ""} continue;             # skip blank lines
    lappend r [string trim [lindex [split $line =] end]]
}
puts $r

That will give one list with just the bits after the equals sign. If you treat it as a string, then it works as a string with each element of the list separated by a space.

Upvotes: 1

Related Questions