I have a question regarding possibility of getting string after specific character in TCL.
Whan I mean is :
Input:
abcdefgh = hgfedcba
Output:
hgfedcba
(return everything after "=" without possible whitespaces)
This is what I was using:
regexp {abcdefgh=\s+"(.*)"} $text_var all variable
In some cases it is ok (with spaces) but when there is no whitespaces then it is not working.
Assuming
% set s {abcdefgh = hgfedcba}
# => abcdefgh = hgfedcba
(or the same thing without one or both of the blanks) you could do one of these:
% scan $s {%*[^=]= %s}
# => hgfedcba
(Scan the string for a substring not containing "=", then advance past the equals sign and optional whitespace, then return the rest of the string.)
string trim [lindex [split $s =] 1]
(Split the string at the equals sign, return the (whitespace-trimmed) second resulting element.)
string trim [string range $s [string first = $s]+1 end]
(Return the (whitespace-trimmed) substring starting after the equals sign.)
string trim [lindex [regexp -inline {[^=]+$} $s] 0]
(Return the (whitespace-trimmed) first match of one or more characters, not including the equals sign, anchored on the end of the string.)
lindex [regexp -inline -all {[a-h]+} $s] 1
(Return the second match of consecutive characters from the set "a" to "h".)
string trimleft [string trimleft $s {abcdefgh }] {= }
(Remove all characters from the start of the string that occur in the set "a" to "h" and blank, then remove from start of the resulting string any characters that are equals sign or blank.)
% regexp {abcdefgh\s*=\s*(\S+)} "abcdefgh = hgfedcba" all variable
1
% set variable
hgfedcba
% regexp {abcdefgh\s*=\s*(\S+)} "abcdefgh=hgfedcba" all variable
1
% set variable
hgfedcba
%
Related
Input string : 4567-ABC
I want to remove everything before "-" in the string so that Output will be ABC.
Output: ABC
If you want to avoid regular expressions:
set string 4567-ABC
set output [lindex [split $string "-"] 1]
The split command takes a string and split characters as the arguments and returns a list.
string last is useful here:
set string 4567-ABC
set idx [string last "-" $string]
set wanted [string range $string $idx+1 end]
Or without the intermediate variable
set wanted [string range $string [string last "-" $string]+1 end]
That even works if the original string does not contain any hyphens.
I have the below line:
^ 1 0.02199 0.03188 0.03667 0.00136 0.04155 0.00000 1.07223 1.07223 -0.47462 0.00335 -0.46457 buf_63733/Z DCKBD1BWP240H11P57PDULVT -
I want to replace column 3 with a different value and to keep the entire line with spaces as is.
I tried lreplace - but spaces deleted.
string map can only replace a word but didn't find a way to replace exact column.
Can someone advice?
Assuming the columns are separated by at least 2 spaces, you could use something like:
set indices [regexp -all -indices -inline {\S+(?:\s\S+)?\s{2,}} $line]
set colCount 1
set newValue 0.01234
foreach pair $indices {
if {$colCount == 3} {
lassign $pair start end
set column [string range $line $start $end]
set value [string trimright $column]
set valueEnd [expr {$end-[string length $column]+[string length $value]}]
set newLine [string replace $line $start $valueEnd $newValue]
} elseif {$colCount > 3} {
break
}
incr colCount
}
You can change the newValue to something else or the newLine to line if you don't need the old line.
Another method uses regsub to inject a command into the replacement string, and then subst to evaluate it. This is like perl's s/pattern/code/e
set newline [subst [regsub {^((?:\s+\S+){2})(\s+\S+)} $line \
{\1[format "%*s" [string length "\2"] $newvalue]}]]
This looks as expected:
set a 1
puts [string match $a $a]
>> 1
However I find this unexpected:
set b {[1]}
puts [string match $b $b]
>> 0
Can you help explain the above behaviour?
The pattern [1] is a bracket expression that matches the characters inside the brackets. In this case, the only string that will match the pattern is 1.
% set b {[1]}
[1]
% puts [string match $b $b]
0
% puts [string match $b "1"]
1
%
If you'd like to compare two strings to see if they are identical, use string equal ... instead.
If you are in a unix shell environment, man n string or man 3tcl string should bring up a manual page with details about the string command.
I have this string:
svpts-7-40.0001
And I need to remove the second '-' from this.
Basically I am fetching values like these which would come with double '-' SOMETIMES. So if such variables are seen then I have to remove the second '-' and replace the same with '.' , so the string should look like:
svpts-7.40.0001
[EDIT] I have tried:
% set list1 [split $string -]
svpts 7 40.0001
% set var2 [join $list1 .]
svpts.7.40.0001
%
Here's a regular expression that will change only the 2nd hyphen:
% regsub -expanded {( .*? - .*? ) -} "svpts-7-40.0001" {\1.}
svpts-7.40.0001
% regsub -expanded {( .*? - .*? ) -} "svpts-7_40.0001" {\1.}
svpts-7_40.0001
% regsub -expanded {( .*? - .*? ) -} "svpts-7-40.0001-a-b-c" {\1.}
svpts-7.40.0001-a-b-c
Try
% set data svpts-7-40.0001
svpts-7-40.0001
% regexp {([^-]*-)(.*)} $data -> a b
1
% set b [string map {- .} $b]
7.40.0001
% set newdata $a$b
svpts-7.40.0001
The above code changes every hyphen after the first. To change only the second hyphen, one can do this:
set idx [string first - $data [string first - $data]+1]
set newdata [string replace $data $idx $idx .]
or this:
set idxs [lindex [regexp -inline -all -indices -- - $data] 1]
set newdata [string replace $data {*}$idxs .]
The first snippet is well-behaved if the data string doesn't contain at least two hyphens; the other needs some kind of checking to avoid throwing an error.
Documentation:
lindex,
regexp,
set,
string,
{*} (syntax),
Syntax of Tcl regular expressions
Syntax of Tcl index expressions:
integer zero-based index number
end the last element
end-N the nth element before the last element
end+N the nth element after the last element (in practice, N should be negative)
M-N the nth element before element m
M+N the nth element after element m
There can be no whitespace within the expression.
I have a string in this pattern:
2(some_substring) -> 3(some_other_substring)
Now these number can be anything.
I think this answer would solve the problem. But it gives all the integers in one variable. I want them to be in different variables, so that I can analyze them. Can we split it? But Splitting would cause problem:
If the the numbers are not single-digit, then the splitting will be erroneous.
Is there any other way?
You can use a variation of this: instead of removing the non-digit characters, you can extract all digit characters into a list:
set text {2(some_substring) -> 3(some_other_substring)}
set numbers [regexp -all -inline -- {[0-9]+} $text]
puts $numbers
# => 2 3
And to get each number, you can use lindex:
puts [lindex $numbers 0]
# => 2
Or in versions 8.5 and later, you can use lassign to assign them to specific variable names:
lassign $numbers first second
puts $first
# => 2
puts $second
# => 3
In regexp -all -inline -- {[0-9]+} $text, -all extract all the matches, -inline puts the matches into a list, -- ends the options, [0-9]+ matches at least one integer.
To extend Jerry's answer, in case digits can appear within the parentheses, a regular expression to only extract digits that are immediately followed by an open parenthesis is: {\d+(=\()}
% set text {2(some_6substring) -> 3(some_other_5substring)}
2(some_6substring) -> 3(some_other_5substring)
% lassign [regexp -all -inline {\d+(?=\()} $text] first second
% set first
2
% set second
3
This assumes that you don't have nested parentheses.