How to check that string is a single word?
Is this right way to do that?
set st "some string"
if { [llength $st] != 1 } {
puts "error"
}
According to one possible definition, you check if a string is one word by using:
catch {set oneWord 0;set oneWord [expr {[llength $string] == 0}]}
That's the Tcl language definition of a word.
On the other hand, if your preferred definition is “is alphanumeric” then you have other possibilities, such as:
# -strict excludes the empty string (normally included for historic reasons)
set oneWord [string is alnum -strict $string]
My answer is based on the assumption that a word contains only alphabet characters.
If you don't mind using some regexp, you can use this:
set st "some string"
if { ![regexp {^[A-Za-z]+$} $st] } {
puts "error"
}
[regexp expression string] returns 0 if there is no match and 1 is there is a match.
The expression I used is ^[A-Za-z]+$ which means the string starts with a letter and can contain any number of letters and must end with a letter. If you want to include a dash inside (e.g. co-operate is one word), you add it in the character class:
^[A-Za-z-]+$
If you are now worried about trailing spaces, I would suggest trimming it first before passing it to the regexp:
set st " some string "
if { ![regexp {^[A-Za-z]+$} [string trim $st]] } {
puts "error"
}
or if you want to directly use the regexp...
set st " some string "
if { ![regexp {^\s*[A-Za-z]+\s*$} $st] } {
puts "error"
}
EDIT: If a word is considered as a string of characters except space, you can do something else: check if the string contains a space.
set st "some strings"
if { [regexp { } $st] } {
puts "error"
}
If it finds a space, regexp will return 1.
regexp provides a straight forward way to match a word with \w and \W. \w matches a word character, while \W matches any character except a word character.
set st "some string"
if { [regexp {\W} $st] } {
puts "error"
}
However \w matches only digits, alphabets and _ (in any combination). If special characters are there in your word, this will not work.
Related
I am trying to find multiple string patterns in a string in TCL. I cannot get the correct and optimized way to do that.
I have tried some code and it is not working
I have to find -h ,-he,-hel ,-help in the string -help
set args "-help"
set res1 [string first "-h" $args]
set res2 [ string first -he $args]
set res3 [string first -hel $args]
set res4 [string first "-help" $args"]
if { $res1 == -1 || $res2 || $res3 || $res4 } {
puts "\n string not found"
} else {
puts "\n string found"
}
how to use regexp here I am not sure , so need some inputs.
The expected output is
This is a case where using regexp is easier. (Asking if a string is a prefix of -help is a separate problem.) The trick here is to use ? and (…) (or rather (?:…) which is the non-capturing version) in the RE and you must use the -- option because the RE begins with a -:
if {[regexp -- {-h(?:e(?:lp?)?)?} $string]} {
puts "Found the string"
} else {
puts "Did not find the string"
}
If you want to know what string you actually found, add in a variable to pick up the overall match:
if {[regexp -- {-h(?:e(?:lp?)?)?} $string matched]} {
puts "Found the string '$matched'"
} else {
puts "Did not find the string"
}
If you instead want the indices where it matched, you need an extra option:
if {[regexp -indices -- {-h(?:e(?:lp?)?)?} $string match]} {
puts "Found the string at $match"
} else {
puts "Did not find the string"
}
If you were instead interested in whether the string was a prefix of -help, you instead should do:
if {[string equal -length [string length $string] $string "-help"]} {
puts "Found the string"
} else {
puts "Did not find the string"
}
Many uses of this sort of thing are actually doing command line parsing. In that case, the tcl::prefix command is very useful. For example, tcl::prefix match finds the entry in a list of options that a string is a unique prefix of and generates an error message when things are ambiguous or simply don't match; the result can be switched on easily:
set MY_OPTIONS {
-help
-someOtherOpt
}
switch [tcl::prefix match $MY_OPTIONS $string] {
-help {
puts "I have -help"
}
-someOtherOpt {
puts "I have -someOtherOpt"
}
}
How can I get a single string variable with spaces in it in TCL to be interpreted as multiple arguments? I can't change the proc definition.
Here is an example of what I mean:
set my_options ""
if { "$some_condition" == 1 } {
append my_options " -optionA"
}
if { "$some_other_condition" == 1 } {
append my_options " -optionB"
}
set my_options [string trim $my_options]
not_my_proc ${my_options} ;# my_options gets interpreted as a single arg here and causes a problem:
# Flag '-optionA -optionB' is not supported by this command.
This is where you use the argument expansion syntax:
not_my_proc {*}$my_options
# ..........^^^
Although I'd recommend using a list instead of a string:
if for some reason the my_options string is not a well-formed list, you'll see an error thrown
if any of the options takes a space, a list is the proper data structure:
set my_options [list]
lappend my_options {-option1}
lappend my_options {-option2 "with a parameter"}
not_my_proc {*}$my_options
How can I remove a part of the text file if the pattern I am searching is matched?
eg:
pg_pin (VSS) {
direction : inout;
pg_type : primary_ground;
related_bias_pin : "VBN";
voltage_name : "VSS";
}
leakage_power () {
value : 0;
when : "A1&A2&X";
**related_pg_pin** : VBN;
}
My pattern is related_pg_pin. If this pattern is found i want to remove that particular section(starting from leakage power () { till the closing bracket}).
proc getSection f {
set section ""
set inSection false
while {[gets $f line] >= 0} {
if {$inSection} {
append section $line\n
# find the end of the section (a single right brace, #x7d)
if {[string match \x7d [string trim $line]]} {
return $section
}
} else {
# find the beginning of the section, with a left brace (#x7b) at the end
if {[string match *\x7b [string trim $line]]} {
append section $line\n
set inSection true
}
}
}
return
}
set f [open data.txt]
set g [open output.txt w]
set section [getSection $f]
while {$section ne {}} {
if {![regexp related_pg_pin $section]} {
puts $g $section
}
set section [getSection $f]
}
close $f
close $g
Starting with the last paragraph of the code, we open a file for reading (through the channel $f) and then get a section. (The procedure to get a section is a little bit convoluted, so it goes into a command procedure to be out of the way.) As long as non-empty sections keep coming, we check if the pattern occurs: if not, we print the section to the output file through the channel $g. Then we get the next section and go to the next iteration.
To get a section, first assume we haven't yet seen any part of a section. Then we keep reading lines until the end of the file is found. If a line ending with a left brace is found, we add it to the section and take a note that we are now in a section. From then on, we add every line to the section. If a line consisting of a single right brace is found, we quit the procedure and deliver the section to the caller.
Documentation:
! (operator),
>= (operator),
append,
close,
gets,
if,
ne (operator),
open,
proc,
puts,
regexp,
return,
set,
string,
while,
Syntax of Tcl regular expressions
Syntax of Tcl string matching:
* matches a sequence of zero or more characters
? matches a single character
[chars] matches a single character in the set given by chars (^ does not negate; a range can be given as a-z)
\x matches the character x, even if that character is special (one of *?[]\)
Here's a "clever" way to do it:
proc unknown args {
set body [lindex $args end]
if {[string first "related_pg_pin" $body] == -1} {puts $args}
}
source file.txt
Your data file appears to be Tcl-syntax-compatible, so execute it like a Tcl file, and for unknown commands, check to see if the last argument of the "command" contains the string you want to avoid.
This is clearly insanely risky, but it's fun.
I'm trying to match a file that looks like this:
22.000 abc_/dasdf
23.652 abc_1/dasdf_0/l
The regular expression I used is this:
[regexp { (\S+)\s+(.+) } $line -> number name }
However, it only matches when there is a space after the string in the file. For example, it returns a match when:
22.000 abc_/dasdf<space>
But no match when there is nothing after /dasdf. By default, there are no such spaces after the string inside the file. Any reason why this could be?
That's because you have spaces inside the braces. Those are significant.
Use
regexp {(\S+)\s+(.+)} $line -> number name
# ......^...........^ no spaces here
or if you want whitespace for readability:
regexp -expanded { (\S+) \s+ (.+) } $line -> number name
In Tcl, we are using the backslash for escaping special characters as well as for spreading long commands across multiple lines.
For example, a typical if loop can be written as
set some_Variable_here 1
if { $some_Variable_here == 1 } {
puts "it is equal to 1"
} else {
puts "it is not equal to 1"
}
With the help of backslash, it can be written as follows too
set some_Variable_here 1
if { $some_Variable_here == 1 } \
{
puts "it is equal to 1"
} \
else {
puts "it is not equal to 1"
}
So, with backslash we can make the statements to be treated as if like they are in the same line.
Lets consider the set statement
I can write something like as below
set x Albert\ Einstein;# This works
puts $x
#This one is not working
set y Albert\
Einstein
If I try with double quotes or braces, then the above one will work. So, is it possible to escape the newline with backslashes without double quotes or braces?
A backslash-newline-whitespace* sequence (i.e., following whitespace is skipped over) is always replaced with a single space. To get a backslash followed by a newline in the resulting string, use \\ followed by \n instead.
set y Albert\\\nEinstein