TCL : find and remove all characters in a string from the first occurrence of a character in a string - tcl

I am a newbie in TCL and in need of a TCL method / utility / code which can find and remove all characters (including itself) in a string from its first occurrence in a string.
I have a string like below:
Func::set()->method();
In the above string I need to find first occurrence of '(' and remove all it and after that so that the resultant string would be just:
Func::set

You can do it with a regular expression:
set the_string [regsub {\(.*} $the_string ""]
or if you're not familiar with regexp then you can do it the more traditional way:
set the_string [
string range $the_string 0 [
expr {[string first "(" $the_string]-1}
]
]
For further info, read the manual pages for [string], [regsub] and [re_syntax].

Another technique is to use split and lindex:
set the_string [lindex [split $the_string "("] 0]
This is short and simple, but may do a lot of extra work if your string is very long.

Related

Removing everything before a certain character in TCL

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.

How to split string by numerics

I havetried to split but still failed.
set strdata "34a64323R6662w0332665323020346t534r66662v43037333444533053534a64323R6662w0332665323020346t534r66662v430373334445330535"
puts [split $strdata "3334445330535"] ;#<---- this command does not work
The result needed as below:
{34a64323R6662w0332665323020346t534r66662v43037} {34a64323R6662w0332665323020346t534r66662v43037}
The split command's optional second argument is interpreted as a set of characters to split on, so it really isn't going to do what you want. However, there are other approaches. One of the simpler methods of doing what you want is to use string map to convert the character sequence into a character that isn't in the input data (Unicode is full of those!) and then split on that:
set strdata "34a64323R6662w0332665323020346t534r66662v43037333444533053534a64323R6662w0332665323020346t534r66662v430373334445330535"
set splitterm "3334445330535"
set items [split [string map [list $splitterm "\uFFFF"] $strdata] "\uFFFF"]
foreach i $items {
puts "==> $i"
}
# ==> 34a64323R6662w0332665323020346t534r66662v43037
# ==> 34a64323R6662w0332665323020346t534r66662v43037
# ==> {}
Note that there is a {} (i.e., an empty-string list element) at the end because that's the string that came after the last split element. If you don't want that, add a string trimright between the string map and the split:
# Doing this in steps because the line is a bit long otherwise
set mapped [string map [list $splitterm "\uFFFF"] $strdata]
set trimmed [string trimright $mapped "\uFFFF"]
set items [split $trimmed "\uFFFF"]
The split command doesn't work like that, see the documentation.
Try making the data string into a list like this:
regsub -all 3334445330535 $strdata " "
i.e. replacing the delimiter with a space.
Documentation:
regsub,
split

Remove prefix substring from string

I have a string abc.def.ghi.j and I want to remove abc. from that, so that I have def.ghi.j.
1) What would be the best approach to remove such a prefix which has a specific pattern?
2) Since in this case, abc is coincidentally the prefix, that probably makes things easier. What if we wanted abc.ghi.j as the output?
I tried it with the split method like this
set name abc.def.ghi.j
set splitVar [split $name {{abc.}} ]
The problem is that it splits across each of a, b, c and . seperately instead of as a whole.
Well, there's a few ways, but the main ones are using string replace, regsub, string map, or split-lreplace-join.
We probably ought to be a bit careful because we must first check if the prefix really is a prefix. Fortunately, string equal has a -length operation that makes that easy:
if {[string equal -length [string length $prefix] $prefix $string]} {
# Do the replacement
}
Personally, I'd probably use regsub but then I'm happy with using RE engine tricks.
Using string replace
set string [string replace $string 0 [string length $prefix]-1]
# Older versions require this instead:
# set string [string replace $string 0 [expr {[string length $prefix]-1}]]
Using regsub
# ***= is magical and says "rest of RE is simple plain text, no escapes"
regsub ***=$prefix $string "" string
Using string map
# Requires cunning to anchor to the front; \uffff is unlikely in any real string
set string [string map [list \uffff$prefix ""] \uffff$string]
Using split…join
This is about what you were trying to do. It depends on the . being a sort of separator.
set string [join [lrange [split $string "."] 1 end] "."]

TCL command - string trim

I was using the command 'string trimright' to trim my string but I found that this command trims more than required.
My expression is "dssss.dcsss" If I use string trim command to trim the last few characters ".dcsss", it trims the entire string. How can I deal with this?
Command:
set a [string trimright "dcssss.dcsss" ".dcsss"]
puts $a
Intended output:
dcsss
Actual output
""
The string trimright command treats its (optional) last argument as a set of characters to remove (and so .dcsss is the same as sdc. to it), just like string trim and string trimleft do; indeed, string trim is just like using both string trimright and string trimleft in succession. This makes it unsuitable for what you are trying to do; to remove a suffix if it is present, you can use several techniques:
# It looks like we're stripping a filename extension...
puts [file rootname "dcssss.dcsss"]
# Can use a regular expression if we're careful...
puts [regsub {\.dcsss$} "dcssss.dcsss" {}]
# Do everything by hand...
set str "dcssss.dcsss"
if {[string match "*.dcsss" $str]} {
set str [string range $str 0 end-6]
}
puts $str
If what you're doing really is filename manipulation, like it looks like, do use the first of these options. The file command has some really useful commands for working with filenames in a cross-platform manner in it.

Is there an equivalent in Tcl of 'string to X' functions found in C stdlib.h?

There are standard functions such as atof and atoi in C's stdlib.h for converting strings to floats / integers (and to do the reverse too). Is there an equivalent of this in Tcl or do I need to write my own process for carrying out these tasks?
Everything is a string in Tcl, but functions that expect a number (like expr) will use that 'string' as an integer:
% set str " 123 "
123
% set num [expr $str*2]
246
If you want to format a number in a specific way (like producing a floating a point number of a specific precision) then you can use format:
% set str " 1.234 "
1.234
% set fnum [format "%.2f" $str]
1.23
As noted, everything is a string in Tcl, so you can just use a given string as an integer or whatever else you need it as. The only caveat being that it needs to be something that can be interpreted as what you want to use it as (ie, you can use "a" as an integer)
You can test to see if something can be interpreted as the type you want using the string is subcommand:
string is integer "5" ;# true
string is integer "a" ;# false
string is list "a b cc" ;# true
string is list "{a b}c" ;# false
I should note as well that equivatents to atof and atoi can be viewed as conversion of internal Tcl data structures to external binary representations. This is done by the [binary format] command.
One can test string is double $x before using $x in expressions.
E.g., [string is double 1.2.3] returns 0
In my case, this code worked:
set a [string trimleft $a 0]