I have this code:
set l [concat a b c "\r\n"]
puts "[llength $l]:$l"
I like to add "\r\n" as the last element of the list, but it seems it is removed:
>tclsh try.tcl
3:a b c
Any reason of that?
Both \r (carriage return) and \n (newline) are whitespace characters according to Tcl's rules, so the whitespace character stripping rules of concat remove them from leading and trailing positions. As the documentation says (emphasis mine):
This command joins each of its arguments together with spaces after trimming leading and trailing white-space from each of them.
If you want that extra two-character EOL-sequence on the end of your list where it won't affect the values in the list, just append it afterwards:
set l [concat a b c]
append l "\r\n"
puts "$l:[llength $l]"
On the other hand, if you want that string as a list element, lappend it as that will automatically add all the quoting required. Also bear in mind that concat isn't a true list concatenation operation (it does complicated string operations); the true list concatenation is:
set concatenated [list {*}$listA {*}$listB]
In Tcl, list elements are separated by spaces or newlines. So having newline alone doesn't mandate it to be separate element. You should nest the list element and then it will work.
% set l [concat a b c [list "\r\n"]]
a b c {
}
% puts "[llength $l]:$l"
4:a b c {
}
%
The concat command returns a string which is a prettified list with a single space between elements and no whitespace before the first element or after the last.
What you're looking for is the list command:
% set l [list a b c "\r\n"]
a b c {
}
% puts [llength $l]:$l
4:a b c {
}
Documentation:
concat,
list
Related
how to find the count of uppercase amd lower case in tcl
with this code im getting only ascii values
foreach character {H e l l o T C L} {
scan $character %c numeric
puts "ASCII character '$numeric' displays as '$character'."
}
Instead of looping through a string yourself, you can use regexp to give you a count:
set str "Hello Tcl"
puts "Uppercase: [regexp -all {[[:upper:]]} $str]"
puts "Lowercase: [regexp -all {[[:lower:]]} $str]"
I'm using [[:upper:]] and [[:lower:]] instead of [A-Z] and [a-z] because the former will correctly capture unicode upper- and lowercase, rather than just the ones in the ASCII set.
You can test each character with string is upper $character and string is lower $character. Note that non-alphabetic characters are neither upper or lower case. For more info check the documentation at https://www.tcl-lang.org/man/tcl8.6/TclCmd/string.htm#M10
Is there a way to add strings (words) that end with a semi-colon to a list without it being a single-item list itself?
I'm working with strings and breaking them into words; and the punctuation often is attached as a suffix. I need to have the words both ways, that is with and without the punctuation.
Is it okay to simply let it a be a list within a list, and just reference all of the words as if they were single-item lists? It appears to work. Or is there a better method altogether?
Thank you.
set list { a; b c d }
chan puts stdout $list; # a; b c d
set new "b;"
lset list 1 $new
chan puts stdout $list; # {a;} {b;} c d
chan puts stdout [lindex [lindex $list 1] 0]; # b;
chan puts stdout [lindex [lindex $list 3] 0]; # d
chan puts stdout [lindex $new 0]; # b;
I'm working with strings and breaking them into words
It is important to use split for this step, other than that, you should be fine using the so-produced list by appending to it. The various list commands will make sure that special characters (your ;) will be protected from being ill-interpreted.
From the Tcl perspective, there is no difference between a single-element list {a;} and an atomic string a;. To quote the Tclers' Wiki:
No program can tell the difference between the string "a" and the
one-element list "a", because the one-element list "a" is the string
"a".
Don't let the curly braces confuse you.
How to escape special characters(e.g "[]") while using search?
Consider the following scenario:
>> set L { a b c [] }
>> a b c []
>> lsearch $L b
>> 1
>> lsearch $L "[]"
>> -1
I'm looking to get 3 when I run lsearch $L "[]"
When looking for fixed strings rather than patterns, it is easiest to use the -exact option to lsearch. You also need to make sure Tcl doesn't do substitution on the search string, for example by enclosing it inside curly braces. Otherwise you'll tell Tcl to look for an empty string (the result of executing an empty command string):
lsearch -exact $L {[]}
There are 4 empty space in my file,set in wr_fp.I want to catch four empty space in code. But below code is not working.
while {[gets $wr_fp line3] >= 0} {
if {[regexp "\n\s+\n\s+\n\s+\n" $line3]} { puts "found 4 empty lines"}
}
tl;dr: Don't put REs in "quotes", put them in {braces}.
The problem is that you've put your RE in quotes, so that it is actually this:
s+
s+
s+
Because of Tcl's general substitution rules, \n becomes a newline and \s becomes a simple s. Putting the RE in braces inhibits this (unwanted in this case) behaviour.
this is my answer.I want this.
while {[gets $rd_fp line] >= 0} {
if {[string match "" $line]} {
if {[expr $count % 4] == 1} {puts "found 4 space"}
incr count
}
}
The gets / chan gets command reads one line at a time and discards the newline character from each line, so your test will never succeed. You need to read in the full contents of the file at once:
set txt [chan read $wr_fp]
if {[regexp {\n\s+\n\s+\n\s+\n} $txt]} { puts "found 4 empty lines"}
Note that you need to use braces around the regular expression as Donal explains.
On some typical pitfalls of RE formulation:
do you really intend to specify that there must be at least one whitespace character on each 'empty' line? If you want to allow lines with no characters at all between the newlines, use \s* instead of \s+.
Also note that this regular expression will match ranges with more than four newlines: the extra newlines will be consumed by one of the \s+ groups. If you want to disallow extra newlines, match with (e.g.) [ \t\f\r] (or any other combination of whitespace you want) instead of \s. Note that this means the expression will match exactly three lines with nothing but blanks, tabs, form feeds, and returns, the lines surrounded and separated by newlines: you might want to extend it with one more subgroup to match the fourth line.
I'm a bit mystified by your solution as described in your own answer, since it doesn't do what was specified in the question. With the following text file:
abc
def
ghi
jkl
mno
pqr
stu
vwx
yz.
(where there is a tab character in the second line after "pqr")
and assuming count has the value 0 when the code is called, your code outputs "found 4 space" after reading the blank lines after "def", "pqr", and "vwx", but not after the line before "stu", where your question indicated it should be.
This code
set count 0
while {[gets $rd_fp line] >= 0} {
if {[string is space $line]} {
incr count
if {$count == 4} {puts "found 4 space"}
} else {
set count 0
}
}
does do what you asked for (nearly): it accepts lines containing whitespace as empty, and it prints its message only after finding four consecutive empty lines. The major difference from the specification in your question is that it also accepts lines without any characters as empty. To match your specification, string is space -strict $line should be used instead.
Documentation: chan, gets, if, incr, puts, regexp, set, string, while
Why does the following not match the :
expect {
timeout {puts timedout\n}
\[1\]: {puts matched\n}
}
> expect test.tcl
[1]:
timedout
If I change it and remove the colon the match works:
expect {
timeout {puts timedout\n}
\[1\] {puts matched\n}
}
$ expect test.tcl
[1]
matched
Or if I get rid of the 1st bracket
expect {
timeout {puts timedout\n}
1\]: {puts matched\n}
}
then it matches:
$ expect test.tcl
1]:
matched
It is not the problem with :, but with [.
The [ is special to both Tcl and the Expect pattern matcher so it is particularly messy. To match a literal [, you have to backslash once from Tcl and then again so that it is not treated as a range during pattern matching. The first backslash, of course, has to be backslashed to prevent it from turning the next backslash into a literal backslash!
expect "\\\[" ; #matches literal '['
So, your code should be,
expect {
timeout {puts timedout\n}
\\\[1]: {puts matched\n}
}
You can prefix the ] with a backslash if it makes you feel good, but it is not
necessary. Since there is no matching left-hand bracket to be matched within the
double-quoted string, nothing special happens with the right-hand bracket. It stands for itself and is passed on to the Expect command, where it is then interpreted as the end of the range.
The next set of examples shows the behavior of [ as a pattern preceded by differing numbers of backslashes. If the [ is not prefixed by a backslash, Tcl interprets whatever follows as a command. For these examples, imagine that there is a procedure named XY that returns the string n*w.
expect" [XY]" ; # matches n followed by anything
expect "\[XY]" ; # matches X or Y
expect "\\[XY]" ; # matches n followed by anything followed by w
expect "\\\[XY]" ; # matches [XYl
expect "\\\\[XY]" ; # matches \ followed by n followed ...
expect "\\\\\[XY]" ; # matches sequence of \ and X or Y
The \\[XY] case deserves close scrutiny. Tcl interprets the first backslash to mean that the second is a literal character. Tcl then produces n*w as the result of the XY command. The pattern matcher ultimately sees the four character string n*w. The pattern matcher interprets this in the usual way. The backslash indicates that the n is to be matched literally (which it would even without the backslash since the n is not special to the pattern matcher).
Source : Exploring Expect
The patterns that worked for me:
-exact {[1]:}
-exact "\[1]:"
{\[1]:}
"\\\[1]:"