I am trying to replace the \ with \\ in a string variable which contains a network folder path. script is
regsub -all {'\'} $folderpath {\\} $folderpath
if it is other character i am able to replace, since its \, I am getting problem.
set folderpath [string map {\\ \\\\} $s]
is about five times faster than using regsub.
Note that the file command has several subcommands that can manage a path string regardless of what the separators look like.
Documentation:
file,
string
% set path {C:\Dinesh\Downloads\Movies\Friends}
C:\Dinesh\Downloads\Movies\Friends
% regsub -all {\\} $path {\\\\}
C:\\Dinesh\\Downloads\\Movies\\Friends
%
Related
I'd like to automatically convert URLs, i.e
"https://sc-uat.ct.example.com/sc/" into "https://invbeta.example.com/sc/"
"https://sc-dev.ct.example.com/sc/" into "https://invtest.example.com/sc/"
"https://sc-qa.ct.example.com/sc/" into "https://invdemo.example.com/sc/"
I've tried following code snippet in TCL
set loc "https://sc-uat.ct.example.com/sc/"
set envs(dev) "test"
set envs(uat) "beta"
set envs(qa) "demo"
puts $envs(uat)
regsub -nocase {://.+-(.+).ct.example.com} $loc {://inv[$envs(\1)].example.com} hostname
puts "new location = $hostname"
But the result is: new location = https://inv[$envs(uat)].example.com/sc/
It seems that [$envs(uat)] is NOT evaluated and substituted further with the real value. Any hints will be appreciated. Thanks in advance
But the result is: new location =
https://inv[$envs(uat)].example.com/sc/ It seems that [$envs(uat)] is eval-ed further.
You meant to say: [$envs(uat)] is not evaluated further?
This is because due to the curly braces in {://inv[$envs(\1)].example.com}, the drop-in string is taken literally, and not subjected to variable or command substitution. Besides, you don't want command and variable substitution ([$envs(\1)]), just one of them: $envs(\1) or [set envs(\1)].
To overcome this, you must treat the regsub-processed string further via subst:
set hostname [subst -nocommands -nobackslashes [regsub -nocase {://.+-(.+).ct.example.com} $loc {://inv$envs(\1).example.com}]]
Suggestions for improvement
I advise to avoid the use of subst in this context, because even when restricted, you might run into conflicts with characters special to Tcl in your hostnames (e.g., brackets in the IPv6 authority parts). Either you have to sanitize the loc string before, or, better work on string ranges like so:
if {[regexp -indices {://(.+-(.+)).ct.example.com} $loc _ replaceRange keyRange]} {
set key [string range $loc {*}$keyRange]
set sub [string cat "inv" $envs($key)]
set hostname [string replace $loc {*}$replaceRange $sub]
}
How to extract the username value from this query string (HTTP url-encoded): username=james&password=pwd in Tcl?
I can get it through Java's request.getParameter("username"); but how to get using Tcl?
The first stage is to split the query string up, and form a dictionary of it (which isn't strictly correct, but I'm guessing you don't care about the case where someone puts multiple username fields in the query string!). However, you also need to decode the encoding of the contents, and that's pretty awful:
proc QueryStringToDict {qs} {
set mapping {}
foreach item [split $qs "&"] {
if {[regexp {^([^=]+)=(.*)$} $item -> key value]} {
dict set mapping [DecodeURL $key] [DecodeURL $value]
}
}
return $mapping
}
proc DecodeURL {string} {
# This *is* tricky! The URL encoding of fields is way nastier than you thought!
set mapped [string map {+ { } \[ "\\\[" \] "\\\]" $ "\\$" \\ "\\\\"} $string]
encoding convertfrom utf-8 \
[subst [regsub -all {%([[:xdigit:]]{2})} $string {[format %c 0x\1]}]]
}
set qs "username=james&password=pwd"
set info [QueryStringToDict $qs]
puts "user name is [dict get $info username]"
In 8.7 (currently in alpha) it'll be much simpler to do that inner encoding; there won't need to be that subst call in there for example. But you haven't got that version of Tcl; nobody has (except for people who insist on being right on the bleeding edge and get themselves into trouble over it).
Assuming this is a CGI environment, where the environment will contain
REQUEST_METHOD=GET
QUERY_STRING='username=james&password=pwd'
or
REQUEST_METHOD=POST
CONTENT_LENGTH=27
# and stdin contains "username=james&password=pwd"
then use tcllib's ncgi module
$ cat > cgi.tcl
#!/usr/bin/env tclsh
package require ncgi
::ncgi::parse
array set params [::ncgi::nvlist]
parray params
$ printf "username=james&password=pwd" | env REQUEST_METHOD=POST CONTENT_LENGTH=27 ./cgi.tcl
params(password) = pwd
params(username) = james
$ env REQUEST_METHOD=GET QUERY_STRING='username=james&password=pwd' ./cgi.tcl
params(password) = pwd
params(username) = james
An alternative to Donal's suggestion, sharing the spirit, but building on battery pieces: tcllib rest package:
(1) To process the query (as part of a valid URL)
% package req rest
1.3.1
% set query [rest::parameters ?username=jo%3Dhn]; # http:// is default scheme, ? is minimum URL boilerplate
username jo%3Dhn
(2) Run a URL decoder (e.g., the one by Donal or the one from Rosetta code):
% proc urlDecode {str} {
set specialMap {"[" "%5B" "]" "%5D"}
set seqRE {%([0-9a-fA-F]{2})}
set replacement {[format "%c" [scan "\1" "%2x"]]}
set modStr [regsub -all $seqRE [string map $specialMap $str] $replacement]
return [encoding convertfrom utf-8 [subst -nobackslash -novariable $modStr]]
}
then:
% set info [lmap v $query {urlDecode $v}]
username jo=hn
% dict get $info username
jo=hn
I'm trying to read a file with two variables, username and password, such as:
user1,password1
How can I separate the values and store in different variables?
I have tried this but it seems not to store the string itself.
It seems that it can't see the comma in there.
Another idea was to use \M to match the "," after every string and store that string but it does not work.
Appreciate some help.
set varuser [lsearch -inline -all $userpass "*,"]
set varuser [regexp {,\s+"(.*)"} $userpass all value]
Since a user's password may contain a comma, I would favour a regex approach:
% set line {user1,my,clever,password}
user1,my,clever,password
% lassign [regexp -inline {^(.+?),(.*)$} $line] -> user pass
% set user
user1
% set pass
my,clever,password
Assuming neither as commas (and ignoring the possible need to trim spaces) [split] is simpler than a regexp and may be enough for the task, along with [lassign]:
tcl> set line {user1,password1}
user1,password1
tcl> lassign [split $line ,] user pwd
tcl> puts $user
user1
tcl> puts $pwd
password1
Seems like a basic task, but I want to take a string that ends in something and replace the last 3 letters with something else. Here's my attempt:
set v "this is bob"
set index2 [string length $v]
set index1 [expr $index2 - 3]
set result [string replace $v index1 index2 dog]
puts $result; # I want it to now say "this is dog"
EDIT: Forgot to mention, the error message it gives me is:
bad index "index1": must be integer?[+-]integer? or end?[+-]integer?
while executing
"string replace $v index1 index2 .hdr"
invoked from within
"set result [string replace $v index1 index2 .hdr]"
(file "string_manipulation.tcl" line 7)
Here is one way to do it. Tcl recognizes tokens such as end, end-1, end-2, ... What you want is to replace from end-2 to end:
set v "this is bob"
set result [string replace $v end-2 end "dog"]
# Result now is "this is dog"
Update
If all you want to do is replacing the file extension, then use file rootname to remove the extension, then add your own:
set v filename.arm
set result [file rootname $v].hdr; # Replaces .arm with .hdr
This solution has the advantage of working with extensions of various lengths, not just 3.
Easy, you forgot you were in TCL right near the end. Instead of passing in the values of index1 and index2, you passed in the literal strings "index1" and "index2". So just add the missing dollar signs:
set result [string replace $v $index1 $index2 dog]
Voila! :-)
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.