shorten preg_match(or) code - regex

I was trying to make a program to match the string which must contains number of 0-9 using regex.
This was correct but it somehow seems long. Do anyone has alternatives for this code?
if($str = (preg_match('/[1]/', $str) && preg_match('/[2]/', $str)
&& preg_match('/[3]/', $str) && preg_match('/[4]/', $str)
&& preg_match('/[5]/', $str) && preg_match('/[6]/', $str)
&& preg_match('/[7]/', $str) && preg_match('/[8]/', $str)
&& preg_match('/[9]/', $str) && preg_match('/[0]/', $str))) {
//do something
}

Simply use a character range: [0-9].
if (preg_match('/[0-9]/', $str)) {
echo 'It does.';
} else {
echo 'It doesn\'t.';
}
If you were ever in a situation where you wouldn't want "6" you could even change it to [012345789] if you really want to.
As Floris mentions, your code is pretty confusing - if you want all the characters to be displayed individually at least once, you can simply use strpos with a loop:
<?php
$match = true;
for ($i = 0; $i < 9; $i++) {
if (strpos($string, (string)$i) === false) {
$match = false;
break; //No need to continue the loop - we already got our answer
}
}
if ($match) {
echo 'Yes!';
} else {
echo 'No!';
}
?>
Alternatively, I apparently already gave you a function to do this?

Looks like you have all the conditions ANDed together. In that following lookahead based regex should work for you:
preg_match('/(?=[^0]*0)(?=[^1]*1)(?=[^2]*2)(?=[^3]*3)(?=[^4]*4)(?=[^5]*5)(?=[^6]*6)(?=[^7]*7)(?=[^8]*8)(?=[^9]*9)./', $str)

If you want to make sure that your string contains all the digits 0-9, you should probably strip anything that is not a digit, then take unique characters only, and make sure the string length is 10. This is more compact than your expression but not necessarily faster. The php function count_chars does much of this work (using mode = 3):
$str = "12345abcde789d9999969";
preg_match_all('/\d+/', $str, $matches);
$distinct = strlen(count_chars(join($matches[0]),3));
if($distinct==10)
{
echo "all ten digits are present<br>";
}
else
{
echo "not all digits are present<br>";
}
echo "there are " . $distinct . " distinct digits<br>";
Output of the above:
not all digits are present
there are 9 distinct digits

Related

Matching all characters in a string except one in any position

How to match (preferably in perl) all strings that match the query string except one character?
Query: TLAQLLLDK
Want to match: xLAQLLLDK, TxAQLLLDK, TLxQLLLDK, etc.
Where 'x' is any capital letter '[A-Z]'.
Use alternation operator.
^(?:[A-Z]LAQLLLDK|T[A-Z]AQLLLDK|TL[A-Z]QLLLDK|.....)$
Likewise fill all..
You can do that by writing a terrible regular expression, which will be horribly slow to build and even slower to execute, or you can just don't use regexes for things like these and write a function that just compares both strings character after character, allows for one "mistake" and returns True only if there was exactly one mistake.
How to match (preferably in perl) all strings that match the query string except one character?
Expanding the answer of #Avinash, by generating the required regular expression dynamically at run time:
my $query = 'TLAQLLLDK';
my $re_proto = '(' . join( '|', map { (my$x=$query)=~s/^(.{$_})./$1\[A-Za-z]/; $x; } (0 .. length($query)-1) ) . ')';
my $re = qr/^$re_proto$/;
my #input = qw(xLAQLLLDK TxAQLLLDK TLxQLLLDK);
my #matches = grep { /$re/ } #input;
print "#matches\n";
(I had to include the [a-z] too, since your example input uses the x as the marker.)
If you need to do that very often, I would advise to cache the generated regular expressions.
Is this what you are looking for?
#!/usr/bin/perl
use strict;
my #str = ("ULAQLLLDK","TAAQLLLDK","TLCQLLLDK","TLAQLLLDK");
while(<#str>){
if (/[A-S,U-Z]LAQLLLDK|T[A-K,M-Z]AQLLLDK|TL[B-Z]QLLLDK/ ){
print "$_\n";
}
}
output:
ULAQLLLDK
TAAQLLLDK
TLCQLLLDK
There are only 9 x 25 = 225 such strings, so you may as well generate them all and put them in a hash for comparison
use strict;
use warnings;
use 5.010;
my %matches;
my $s = 'TLAQLLLDK';
for my $i (0 .. length($s) - 1) {
my $c = substr $s, $i, 1;
for my $cc ('A' .. 'Z') {
substr(my $ss = $s, $i, 1) = $cc;
++$matches{$ss} unless $cc eq $c;
}
}
printf "%d matches found\n", scalar keys %matches;
for ( qw/ TLAQLLLDK TLAQLXLDK / ) {
printf "\$matches{%s} = %s\n", $_, $matches{$_} // 'undef';
}
output
225 matches found
$matches{TLAQLLLDK} = undef
$matches{TLAQLXLDK} = 1

Detect Blank with Regex

I am using the following regex to check a name field for invalid characters...
if (!preg_match("/^[a-zA-Z ]*$/",$mystring))
Is there a way to also detect if the string is blank using regex? Or am I better off doing that using PHP?
You can just do a simple check without a regex:
if( $string == "") //do something
or
if(strlen($string) == 0) //do something
or
if(strlen(trim($string)) == 0) //do something
Or,
<?php
$str = "\r\n\t\0 ";
if (trim($str) == "") {
echo "This string is blank";
}
Trimming the string of any white space characters, including one or more spaces and then comparing the result to an empty string will detect a blank string. The advantage here is that you need only use one function, namely trim.
One may certainly use trim() and strlen() together to achieve the same result, but that requires two functions instead of one.
Using strlen() without trimming the input $str could lead to accepting a "blank" line, as follows:
<?php
$content = 'Content: ';
$str = " \r\n\t\0 ";
if ( strlen( $str ) == 0) {
echo 'blank line',"\n";
}
else
{
$content .= $str;
}
echo $content;
By not trimming the string of any white space characters the string length in this case is six but the a visibly blank $str gets appended to $content.

How to check for a number in a string using perl

I have a string in a variable $vreponse and the string is
int.force_snmp_version T_SIZE 3
All I want to do is verify if there is number 3 in the string. If the verification is success print a message or else print fail message
I have tried something like this
my $vresponse = $ua->get("https://$user:$pass\#$ern_ip/get_param?p=init.force_snmp_version");
if ($vresponse->decoded_content =~ /\b3$/)
{
print "SUCESS\n";
}
else
{ print "not\n"; }
This is not working, do I need to change $vresponse->decoded_content ?
Maybe just
if ( $vresponse =~ /3/ ) { ... }
which just checks that there is a 3 character somewhere in the string.
Or, more precisely
if ( $vresponse =~ /\b3$/ ) { ... }
which check that the last character is 3 and it is alone, i.e. not the end of, say, 23.
my $vresponse = 'int.force_snmp_version T_SIZE 3';
my $char = '3';
my $result = index($vresponse , $char);
if ($result >=0)
{
#display found
}
else
{
#display not found
}

Perl pattern matching with pattern arithmetic

I want to understand how can I do arithmetic on matched sub-patterns in perl regex.
This is just a sample code and I want to understand how can I use \1 (already matched sub-pattern. in this case - 7) to match pattern+1 (8)
my $y = 77668;
if($y =~ /(\d)\1(\d)\2\1+1/) #How to increment a previously
#matched sub-pattern and form a pattern?
{
print $y;
}
EDIT
From the answers, I see that pattern arithmetic is not possible.
This is what I want to achieve.
I want to form a regex which will match this pattern:
N-3N-2N-1NNN+1N+2N+3 (N = 3,4,5,6
Its possible via regex code blocks:
my $y = 77668;
if($y =~ /(\d)\1(\d)\2(??{$1+1})/ ) {
print $y;
}
In this snippet (??{ CODE }) returns another regex that must match, so this regex looks like "8" ($1+1). As a result, whole regex will match only if 5th digit is greather and 1st by 1. But drawback with 1st digit is 9, this code block will return "10", so possible its wrong behavior, but you said nothing about what must be done in this case.
Now about N-3N-2N-1NNN+1N+2N+3 question, you can match it with this regex:
my $n = 5;
if( $y =~ /(??{ ($n-3).($n-2).($n-1).$n.($n+1).($n+2).($n+3) })/ ){
Or more "scalable" way:
my $n = 5;
if( $y =~ /(??{ $s=''; $s .= $n+$_ foreach(-3..3); $s; })/ ){
Again, what we must do if $n == 2 ?? $n-3 will be -1. Its not a simply digit cus it have sign, so you should think about this cases.
One another way. Match what we have and then check it.
if( $y =~ /(\d)(\d)(\d)(\d)(\d)(\d)(\d)/ ) {
if( $1 == ($4-3) && $2 == ($4-2) && $3 == ($4-1) && $6 == ($4+1) && $7 == ($4+2) && $7 == ($4+3) ) {
#...
Seems this method litle bit clumsy, but its obivious to everyone (i hope).
Also, you can optimize your regex since 7 ascending digits streak is not so frequent combination, plus get some lulz from co-workers xD:
sub check_number {
my $i;
for($i=1; $i<length($^N); $i++) {
last if substr($^N, $i, 1)<=substr($^N, $i-1, 1);
}
return $i<length($^N) ? "(*FAIL)" : "(*ACCEPT)";
}
if( $y =~ /[0123][1234][2345][3456][4567][5678][6789](??{ check_number() })/ ) {
Or... Maybe most human-friendly method:
if( $y =~ /0123456|1234567|2345678|3456789/ ) {
Seems last variant is bingo xD Its good example about not searching regex when things are so simple)
Of course this is possible. We are talking about Perl regexes after all. But it will be rather ugly:
say "55336"=~m{(\d)\1(\d)\2(\d)(?(?{$1+1==$3})|(*F))}?"match":"fail";
or pretty-printed:
say "55336" =~ m{ (\d)\1 (\d)\2 (\d)
(? (?{$1+1==$3}) # true-branch: nothing
|(*FAIL)
)
}x
? "match" : "fail";
What does this do? We collect the digits in ordinary captures. At the end, we use an if-else pattern:
(? (CONDITION) TRUE | FALSE )
We can embed code into a regex with (?{ code }). The return value of this code can be used as a condition. The (*FAIL) (short: (*F)) verb causes the match to fail. Use (*PRUNE) if you only want a branch, not the whole pattern to fail.
Embedded code is also great for debugging. However, older perls cannot use regexes inside this regex code :-(
So we can match lots of stuff and test it for validity inside the pattern itself. However, it might be a better idea to do that outside of the pattern like:
"string" =~ /regex/ and (conditions)
Now to your main pattern N-3N-2N-1NNN+1N+2N+3 (I hope I parsed it correctly):
my $super_regex = qr{
# N -3 N-2 N-1 N N N+1 N+2 N+3
(\d)-3\1-2\1-1\1\1(\d)(\d)(\d)
(?(?{$1==$2-1 and $1==$3-2 and $1==$4-3})|(*F))
}x;
say "4-34-24-144567" =~ $super_regex ? "match" : "fail";
Or did you mean
my $super_regex = qr{
#N-3 N-2 N-1 N N N+1 N+2 N+3
(\d)(\d)(\d) (\d)\4 (\d)(\d)(\d)
(? (?{$1==$4-3 and $2==$4-2 and $3==$4-1 and
$5==$4+1 and $6==$4+2 and $7==$4+3})|(*F))
}x;
say "123445678" =~ $super_regex ? "match" : "fail";
The scary thing is that these even works (with perl 5.12).
We could also generate parts of the pattern at match-time with the (??{ code }) construct — the return value of this code is used as a pattern:
my $super_regex = qr{(\d)(??{$1+1})(??{$1+2})}x;
say "234"=~$super_regex ? "match":"fail"
et cetera. However, I think readability suffers more this way.
If you need more than nine captures, you can use named captures with the
(?<named>pattern) ... \k<named>
constructs. The contents are also available in the %+ hash, see perlvar for that.
To dive further into the secrets of Perl regexes, I recommend reading perlre a few times.

How to determine number of times a word appears in text?

How can I find the number of times a word is in a block of text in Perl?
For example my text file is this:
#! /usr/bin/perl -w
# The 'terrible' program - a poorly formatted 'oddeven'.
use constant HOWMANY => 4; $count = 0;
while ( $count < HOWMANY ) {
$count++;
if ( $count == 1 ) {
print "odd\n";
} elsif ( $count == 2 ) {
print "even\n";
} elsif ( $count == 3 ) {
print "odd\n";
} else { # at this point $count is four.
print "even\n";
}
}
I want to find the number of "count" word for that text file. File is named terrible.pl
Idealy it should use regex and with minimum number of line of code.
EDIT: This is what I have tried:
use IO::File;
my $fh = IO::File->new('terrible.pl', 'r') or die "$!\n";
my %words;
while (<$fh>) {
for my $word ($text =~ /count/g) {
print "x";
$words{$word}++;
}
}
print $words{$word};
Here's a complete solution. If this is homework, you learn more by explaining this to your teacher than by rolling your own:
perl -0777ne "print+(##=/count/g)+0" terrible.pl
If you are trying to count how many times appears the word "count", this will work:
my $count=0;
open(INPUT,"<terrible.pl");
while (<INPUT>) {
$count++ while ($_ =~ /count/g);
}
close(INPUT);
print "$count times\n";
I'm not actually sure what your example code is but you're almost there:
perl -e '$text = "lol wut foo wut bar wut"; $count = 0; $count++ while $text =~ /wut/g; print "$count\n";'
You can use the /g modifier to continue searching the string for matches. In the example above, it will return all instances of the word 'wut' in the $text var.
You can probably use something like so:
my $fh = IO::File->new('test.txt', 'r') or die "$!\n";
my %words;
while (<$fh>) {
for my $word (split / /) {
$words{$word}++;
}
}
That will give you an accurate count of every "word" (defined as a group of characters separated by a space), and store it in a hash which is keyed by the word with a value of the number of the word which was seen.
perdoc perlrequick has an answer. The term you want in that document is "scalar context".
Given that this appears to be a homework question, I'll point you at the documentation instead.
So, what are you trying to do? You want the number of times something appears in a block of text. You can use the Perl grep function. That will go through a block of text without needing to loop.
If you want an odd/even return value, you can use the modulo arithmetic function. You can do something like this:
if ($number % 2) {
print "$number is odd\n"; #Returns a "1" or true
}
else {
print "$number is even\n"; #Returns a "0" or false
}