Check whether string contains fragment in Tcl - string

I have a set of words, e.g. {6-31G*, 6-311G*, 6-31++G*, 6-311++G**}. As you may see, the common fragment is "6-31". What I need to do in Tcl now is to check whether string under $variable contains this fragment. I know I could do it with regular expression like this:
if {[regexp {^6-31} $variable]} {
puts "You provided Pople-style basis set"
}
but what other solution could I use (just out of curiosity)?

Just to check if a string contains a particular substring, I'd use string first
set substring "6-31"
if {[string first $substring $variable] != -1} {
puts "\"$substring\" found in \"$variable\""
}
You can also use glob-matching with string match or switch
switch -glob -- $variable {
*$substring* {puts "found"}
default {puts "not found"}
}

Related

parsing conditional operators as strings and using as conditional operators

my $line ="Corner:Default,Output:fall_delay_slew_1,Mean=34.97p,Std- dev=1.767p,Min=30.02p,Max=39.71p"; #added semicolon
my $my_value="COND = Mean > 3"; #this has come from the parsed file.
$my_value =~ m/(\w+)\s*(.)\s*(\d+)/;
my $cond=$1;
my $sign=$2;
my $value=$3;
print "DEBUG:cond is $cond and sign $sign and value $value \n";
if ( $line =~ m/$cond=(.*?),/) {
if ( "$value $sign $1" ) {
print "$value is $sign than $1\n";
} else {
print "actual value is less\n";
}
}
If you see in the above if statement always evaluates to true.
How can I solve this kind of problem i.e $sign = "<" (could be any operator)
but when I want to compare it with $value I want it to function as an
operator and not as a string.
What you're willing to do (executing a string as code) can be done with
eval. That doesn't mean it is the most appropriate way of doing
it though. Do it only if you guarantee your input safety and check for
it.
A better way would be checking the operator your self and determining
how to proceed. If you use a recent Perl version, the given-when
feature can be handy to do this:
use feature 'switch'; # not needed if you already use 5.010 or greater
given ($sign) {
when ('<') { say "$cond less than $value" }
when ('>') { say "$cond greater than $value" }
default {
warn "unrecognized operator `$sign'\n";
# decide what to do
}
}

Add to integer within string?

I would like to make a string by incrementing a variable within the string.
eg.
$result = "Result: $amount++";
How can this be achieved?
It can be done using trickery.
$result = "Result: ${\( $amount++ )}";
But why would you want to???
$result = "Result: ".$amount++;
If you want to modify a number in a string, you have to use the e modifier for the s operation. This makes Perl evaluating the replacement as an expression.
#! /usr/bin/perl
$_ = "Result: 1\n";
s/\d+/$&+1/e;
print;
It is documented in the Perl manual.
I take it that you have a string that already contains a 'number' (string of digits), and you want to increment that number within.
You'd have to extract the "number" first, in one way or another, since it is merely a string of chars when inside a string; then increment it and join it all back. I'll take it that it is a string of digits bounded by non-digits
my ($pre, $num, $post) = $str =~ m/(\D*)(\d+)(\D*)/;
$str = $pre . ($num+1) . $post;
This makes a critical assumption that the word contains a string of digits in only one place and no digits elsewhere, since if that were not the case the problem would be ill posed.
Just for the curiousity of it I'd like to add a bit to this. A part of a string can be accessed by substr, and that function can be manipulated as an lvalue (can be assigned to). So, if you were to know the starting position and the length of your "number" (what can be found in various ways) you could cram the above process in one statement, if you must
substr($str, $num_beg, $num_len) = substr($str, $num_beg, $num_len) + 1;
or, equally bad
substr($str, $num_beg, $num_len) = ($str =~ m/(\d+)/)[0] + 1;
Now your starting $str string contains the "number" within it incremented. However, this is plain nasty and I cannot recommend any of it. Finally, you can of course find $num_beg and $num_len on the fly, inside of substr, but that is just too much as the poor string would be processed three times in a single statement. (Also, this changes your $str in place, which your question hints is not what you want.)
Added Regex provide the capability to run code in the replacement part, by using /e modifier.
my $str = "ah20bah";
$str =~ s/(\d+)/$1+1/e;
say $str; # it's 'ah21bah'
See this in perlrequick and in perlop.

Is there a string in Perl that is equal to all other strings under eq?

I am running a string equality check like this:
if($myString eq "ExampleString")
Is there a value that myString could have which would cause execution to enter the if structure no matter what the string literal is?
Yes, with objects and overloaded operators:
package AlwaysTrue {
use overload 'eq' => sub { 1 },
'""' => sub { ${+shift} };
sub new {
my ($class, $val) = #_;
bless \$val => $class;
}
}
my $foo = AlwaysTrue->new("foo");
say "foo is =$foo=";
say "foo eq bar" if $foo eq "bar";
Output:
foo is =foo=
foo eq bar
However, "$foo" eq "bar" is false, as this compares the underlying string.
If you mean "any string other than undef", then simply check
if (defined $myString)
If you mean "any string other than undef or empty string", then simply check
if ($myString) # Has a slight bug - will NOT enter if the number 0 passed
#or
if ($myString || $myString == 0) # Avoids the above bug
If you mean ANY ANY string, you don't need an if.... but if you want one anyway:
if (1)
If you mean "any string that isn't looking like a number" (e.g. distinguish "11" from "11a"):
use Scalar::Util qw(looks_like_number);
if (Scalar::Util::looks_like_number($myString))

How explicitly resolve variables in a perl string?

In my perl script I want to have both versions of $config directory:
my $config='$home/client/config';
and
my $config_resolved="$home/client/config";
But I want to get $config_resolved from $config, i.e. something like this:
my $config_resolved=resolve_vars($config);
How can I do such thing in perl?
From the Perl FAQ (which every Perl programmer should read at least once):
How can I expand variables in text strings?
(contributed by brian d foy)
If you can avoid it, don't, or if you can
use a templating system, such as Text::Template or Template Toolkit,
do that instead. You might even be able to get the job done with
sprintf or printf:
my $string = sprintf 'Say hello to %s and %s', $foo, $bar;
However, for the one-off simple case where I don't want to pull out a
full templating system, I'll use a string that has two Perl scalar
variables in it. In this example, I want to expand $foo and $bar to
their variable's values:
my $foo = 'Fred';
my $bar = 'Barney';
$string = 'Say hello to $foo and $bar';
One way I can do this involves the substitution operator and a double /e flag. The
first /e evaluates $1 on the replacement side and turns it into $foo. The
second /e starts with $foo and replaces it with its value. $foo,
then, turns into 'Fred', and that's finally what's left in the string:
$string =~ s/(\$\w+)/$1/eeg; # 'Say hello to Fred and Barney'
The /e will also silently ignore violations of strict, replacing undefined
variable names with the empty string. Since I'm using the /e flag
(twice even!), I have all of the same security problems I have with
eval in its string form. If there's something odd in $foo, perhaps
something like #{[ system "rm -rf /" ]}, then I could get myself in
trouble.
To get around the security problem, I could also pull the
values from a hash instead of evaluating variable names. Using a
single /e, I can check the hash to ensure the value exists, and if it
doesn't, I can replace the missing value with a marker, in this case
??? to signal that I missed something:
my $string = 'This has $foo and $bar';
my %Replacements = (
foo => 'Fred',
);
# $string =~ s/\$(\w+)/$Replacements{$1}/g;
$string =~ s/\$(\w+)/
exists $Replacements{$1} ? $Replacements{$1} : '???'
/eg;
print $string;
I use eval for this.
So, you must replace all scalars (their names) with their values.
$config = 'stringone';
$boo = '$config/any/string';
$boo =~ s/(\$\w+)/eval($1)/eg;
print $boo;
Because you are using my to declare it as private variable, you might as well use a /ee modifier. This can find variables declared to be in local scope:
$boo =~ s/(\$\w+)/$1/eeg;
This is most tidily and safely done by the double-eval modifier on s///.
In the program below, the first /e evaluates the string $1 to get $home, while the second evaluates $home to get the variable's value HOME.
use strict;
my $home = 'HOME';
my $config = '$home/client/config';
my $config_resolved = resolve_vars($config);
print $config_resolved, "\n";
sub resolve_vars {
(my $str = shift) =~ s/(\$\w+)/$1/eeg;
return $str;
}
output
HOME/client/config

perl code behaving strange

I have written a code to get the url of a website and then search for a string and then compare that string(actually a number) with a hardcoded number
#!/usr/bin/perl
use LWP::Simple;
my $oldversion =36;
$pageURL="http://www.google.com/isos/preFCS5.3/LATESTGOODCVP/";
my $simplePage=get($pageURL);
my $newPage = "$simplePage";
my $str = (split("href=\"CVP-LATEST-5.3.0.",$newPage ))[1];
my $version = substr("$str",0,2);
print $version; // HERE IT PRINT 37 WHICH IS CORRECT
if($version =! $oldVersion )
{
print $version; // BUT HERE IT PRINTS 1 WHICH IS WRONG. HOW IS IT CHANGING ?
##-- fetch the zip and save it as perlhowto.zip
my $status = getstore("http://www.google.com/isos/preFCS5.3/LATESTGOODCVP/CVP-LATEST-5.3.0.$version.iso", "CVP-LATEST-5.3.0.$version.iso");
}
else
{
print("Currently new version\n");
}
Why is it changing the value ? its not able to download the file becuase of that.
You mean !=, not =!, which is an assignment of a negation.
Also, split always uses a regex (except for the very special case of a string that has a single space), so those .s in 5.3.0. will match any non-newline. You probably want to \-escape them.
You may be interested in the uscan script in the debian devtools package.
You have got your "not equals" operator backwards. It should be != rather than =!.
By using =! you are in effect saying "set $version to the negated value of $oldversion".
Here is the offending line
if($version =! $oldVersion ) # Should be if($version != $oldVersion )
Also notice that by using the != operator you are telling perl that $version and $oldversion contain numbers. For string comparisons you should use the ne operator, which assumes that these variables contain strings.
if($version ne $oldVersion ) # String inequality
Here is the documentation for equality operators -
http://perldoc.perl.org/perlop.html#Equality-Operators
It's because you are assigning to $version the value !$oldVersion in this "test":
if($version =! $oldVersion )
And $oldVersion is nothing--but $oldversion is 37. You are assigning $version the boolean negation of an undefined variable. Undefined is boolean false, and so the negation is boolean true or 1.
If you read very much on perl, you're bound to come across the advice to use strict and warnings. Had you done that, it would have told you, among other things:
Global symbol "$oldVersion" requires explicit package name at - line 21.
This means that you didn't declare $oldVersion as lexical (my) or package-level (our) in this package, so if you want to use it, please include the package where you're getting it. In a vast majority of cases, a seasoned Perl programmer will recognize this as "Ugh, I didn't declare $oldVersion!" and the reason is that you declared $oldversion.
Your use of split doesn't make a lot of sense here. What you really want are the two digits following the CVP-LATEST-5.3.0. string. You're also not really doing anything by assigning one variable to another with the addition of quotes ($newPage = "$simplePage").
And, of course, as others have pointed out, the comparison is != not =!.
I'd rewrite this as:
use strict;
use warnings;
use LWP::Simple;
my $oldVersion = 36;
my $url = 'http://www.google.com/isos/preFCS5.3/LATESTGOODCVP/';
my $newPage = get($url)
or die "Cannot retrieve contents from $url\n";
if ( $newPage =~ /href=\"CVP-LATEST-5\.3\.0\.(\d\d)/ ) {
my $version = $1;
if ( $version != $oldVersion ) {
my $status = getstore($url . "CVP-LATEST-5.3.0.$version.iso",
"CVP-LATEST-5.3.0.$version.iso");
} else {
print "Already at most recent version\n";
}
} else {
die "Cannot find version tag in contents from $url\n";
}

Resources