tcl puts if format strings - tcl

I want to print a information in a table.
some of the information contain a color code as \033\[1;31m${info}\033\[0m
The method I use to print the content is as below:
set name "arb bul"
set qname black
set phone 123-456789
set print_users az
set name "arbi yu"
set info dod
set string "%-15s%-22s%-15s%-11s%-1s"
puts [format $string $name $qname ${info} ${phone} $print_users]
The problem came out when I try to color one of the strings, the table shift doesn't kept since the next string take into account the spaces from the last characters.
set qname "\033\[1;31mblack\033\[0m"
puts [format $string $name $qname ${info} ${phone} $print_users]
Is there any way to set the string spaces from the beginning of the line?

The format command does not have any knowledge of what the different escape codes may mean to the terminal. Different terminals use different escape codes. If you want to be able to use escape codes in your values, it may be best to also use escape codes to position the strings:
set string "%s\033\[16G%s\033\[38G%s\033\[53G%s\033\[64G%s"

Related

How to insert ASCII control characters into a TCL string?

I need to create a TCL script that contains ASCII control characters. This is the full list of these characters from the ASCII table but I am only interested in putting in the "start of text" value 2 and "end of text" value 3.
You can enter a hex code in a string by writing \xnn where nn is the code, e.g.
set start_of_text "\x02"
set end_of_text "\x03"
See the documentation at https://www.tcl-lang.org/man/tcl8.6/TclCmd/Tcl.htm#M27
You can also use format with the %c code (which might be more useful if you don't know the relevant number until run-time because it's in a variable or whatever):
set ascii(STX) [format %c 2]
set ascii(ETX) [format %c 3]
If I'm going to be wrapping text in a control sequence (often for things like applying a colouring) then I'll make a procedure to do the job:
proc wrapped {string} {
# These use Unicode escapes
return "\u0002$string\u0003"
}
puts [wrapped "this is some test text"]

unable to get return value from MariaDB via perl DBI [duplicate]

I'm getting a bunch of text from an outside source, saving it in a variable, and then displaying that variable as part of a larger block of HTML. I need to display it as is, and dollar signs are giving me trouble.
Here's the setup:
# get the incoming text
my $inputText = "This is a $-, as in $100. It is not a 0.";
print <<"OUTPUT";
before-regex: $inputText
OUTPUT
# this regex seems to have no effect
$inputText =~ s/\$/\$/g;
print <<"OUTPUT";
after-regex: $inputText
OUTPUT
In real life, those print blocks are much larger chunks of HTML with variables inserted directly.
I tried escaping the dollar signs using s/\$/\$/g because my understanding is that the first \$ escapes the regex so it searches for $, and the second \$ is what gets inserted and later escapes the Perl so that it just displays $. But I can't get it to work.
Here's what I'm getting:
before-regex: This is a 0, as in . It is not a 0.
after-regex: This is a 0, as in . It is not a 0.
And here's what I want to see:
before-regex: This is a 0, as in . It is not a 0.
after-regex: This is a $-, as in $100. It is not a 0.
Googling brings me to this question. When I try using the array and for loop in the answer, it has no effect.
How can I get the block output to display the variable exactly as it is?
When you construct a string with double-quotes, the variable substitution happens immediately. Your string will never contain the $ character in that case. If you want the $ to appear in the string, either use single-quotes or escape it, and be aware that you will not get any variable substitution if you do that.
As for your regex, that is odd. It is looking for $ and replacing them with $. If you want backslashes, you have to escape those too.
And here's what I want to see:
before-regex: This is a 0, as in . It is not a 0.
after-regex: This is a $-, as in $100. It is not a 0.
hum, well, I'm not sure what the general case is, but maybe the following will do:
s/0/\$-/;
s/in \K/\$100/;
Or did you mean to start with
my $inputText = "This is a \$-, as in \$100. It is not a 0.";
# Produces the string: This is a $-, as in $100. It is not a 0.
or
my $inputText = 'This is a $-, as in $100. It is not a 0.';
# Produces the string: This is a $-, as in $100. It is not a 0.
Your mistake is using double quotes instead of single quotes in the declaration of your variable.
This should be :
# get the incoming text
my $inputText = 'This is a $-, as in $100. It is not a 0.';
Learn the difference between ' and " and `. See http://mywiki.wooledge.org/Quotes and http://wiki.bash-hackers.org/syntax/words
This is for shell, but it's the same in Perl.

Split camelcase value with TCL

I have this TCL expression:
[string toupper [join [lrange [file split [value [topnode].file]] 1 1]]]
This retrieves companyName value from c:/companyName... and I need to split that value before the first capital letter into Company Name. Any ideas?
Thanks in advance.
That's rather more in one word than I would consider a good idea. It makes the whole thing quite opaque! Let's split it up.
Firstly, I would expect the base company name to be better retrieved with lindex from the split filename.
set companyName [lindex [file split [value [topnode].file]] 1]
Now, we need to process that to get the human-readable version out of it. Alas, that's going be a bit difficult without knowing what's been done to it, but if we use as our example fooBarBoo_grill then we can see what we can do. First, we get the pieces with some regular expressions (this part might need tweaking if there are non-ASCII characters involved, or if certain critical characters need special treatment):
# set companyName "fooBarBoo_grill"
set pieces [regexp -all -inline {[a-z]+|[A-Z][a-z]*} $companyName]
# pieces = foo Bar Boo grill
Next, we need to capitalise. I'll assume you're using Tcl 8.6 and so have lmap as it is perfect for this task. The string totitle command has been around for a very long time.
set pieces [lmap word $pieces {string totitle $word}]
# pieces = Foo Bar Boo Grill
That list might need a bit more tweaking, or it might be OK as it is. An example of tweaking that might be necessary is if you've got an Irish name like O'Hanrahan, or if you need to insert a comma before and period after Inc.
Finally, we properly ought to set companyName [join $pieces] to get back a true string, but that doesn't have a noticeable effect with a list of words made purely out of letters. Also, more complex joins with regular expressions might be needed if you've done insertion of prefixing punctuation (the , Inc. case).
If I was doing this for real, I'd try to have the proper company name expressed directly elsewhere rather than relying on the filename. Much simpler to get right!
To begin with, try using
lindex [file split [value [topnode].file]] 1
The lrange command will return a list, which might cause problems with some directory names. The join command should be pointless if you don't use lrange, and string toupper removes the information you need to do the operation you want to do.
To split before uppercase letters, you can use repetitive matches of either (?:[a-z]+|[A-Z][a-z]+) (ASCII / English alphabet letters only) or (?:[[:lower:]]+|[[:upper:]][[:lower:]]+) (any Unicode letters).
% regexp -all -inline {(?:[a-z]+|[A-Z][a-z]+)} camelCaseWord
camel Case Word
Use string totitle to change the first letter of the first word to upper case.
Documentation:
file,
lindex,
regexp,
string,
Syntax of Tcl regular expressions

TCL output with space

I have 5 different variable coming from different if and loop statements, when I use "put" to take output into text file all characters and digits are altogether like this : alphaclass112098voip. where
variables: name = alpha
category = class1
number = 12098
service = voip
I want output in file as like this with spaces on same line.
Alpha class1 12098 voip
Beta class1 12093 DHCP SIP
Also at certain point I want to through delimiters for future purposes.
The easiest way to deal with this is to construct a Tcl list that represents the record. You can do this piecemeal with lappend, or all at once with list. Or mix them.
foreach name $names category $categories number $numbers service $services {
set record [list $name $category]
lappend record $number
lappend record $service
puts $record
}
This shows the record for each line in a format that Tcl finds easy to parse (you'll see what I mean if you have a name with a space in it). To use a delimiter to separate the values instead, the join command is very useful:
puts [join $record $delimiter]
The default delimiter is space, but try a : instead to see how it works.
If you're generating a CSV file, do use the csv package in Tcllib. It handles the tricky edge-cases (e.g., embedded commas) for you.

How to trim two words from right of a string

I want to remove two words from right of a string.
For example:
set str "sachin is the pride of india"
I need to remove india and of from right and there should be no space after that.
I have tried using string trimright.
The string trimright command is exactly the wrong tool for this; it treats its trim argument as a set of characters to remove, not a literal. The simplest way of doing this is with lreplace, provided the string doesn't contain list metacharacters and you don't care about the number of spaces.
set shortened [lreplace $str end-1 end]
If you need to do it reliably, regular expressions are the tool of choice.
set shortened [regsub {\s*\S+\s+\S+\s*$} $str ""]
Use regsub for this. Please.