Comparison operators in regex - php

Can we use comparison in a regex pattern? I want to check if a recent matched group is greater than a number. This is the pattern: size=(\d+) and I wanna see if (\d+)>200 then return true.

You can't do it with that same syntax, but what you're after is possible with a more complex expression such as:
Greater than 200:
([1-9]\d+|(?!200)[2-9])\d\d
Include 200:
([1-9]\d+|[2-9])\d\d
As you approach other (and larger) numbers, however, it will be unmanagable.
You would do best to match all numbers, then loop through the results to do the > 200 check, and remove ones that don't comply.
Note: The above regular expressions are just to show that matching numbers greater than 200 is possible in pure regex. It is not recommended however, and more complex/variable numbers will be unworkable.
OP mentioned in comments that they would like to match > 30*1024*1024, which is > 31457280
In the name of proving why regex is a pain, I have written the required pattern:
\b((3[1-9][4-9][5-9][7-9][2-9][8-9]\d+)|(3[1-9][4-9][5-9][7-9][3-9]\d{2,})|(3[1-9][4-9][5-9][8-9]\d{3,})|(3[1-9][4-9][6-9]\d{4,})|(3[1-9][5-9]\d{5,})|(3[2-9]\d{6,})|(?!31457280)(4\d{7,}))\b
(not very pretty!)

No, it's not possible, the purpose of the regular expressions is to match expresions not to program with it

Related

PHP PCRE match bigger than, lower than string values

Considering the validation of a input value with PCRE that might contain :
200
<200
>200
<=200
>=200
What would be the best approach to match <= or >= sequence of characters? So far I have this :
[<|>|<=|>=]{0,2}\d+
You are mistaking a character class with the grouping operator. Consider:
(?:<|>|<=|>=)?\d+
Or, if you want to save the groupings for later logic:
(<|>|<=|>=)?(\d+)

Match a^n b^n c^n (e.g. "aaabbbccc") using regular expressions (PCRE)

It is a well known fact that modern regular expression implementations (most notably PCRE) have little in common with the original notion of regular grammars. For example you can parse the classical example of a context-free grammar {anbn; n>0} (e.g. aaabbb) using this regex (demo):
~^(a(?1)?b)$~
My question is: How far can you go? Is it also possible to parse the context-sensitive grammar {anbncn;n>0} (e.g. aaabbbccc) using PCRE?
Inspired by NullUserExceptions answer (which he already deleted as it failed for one case) I think I have found a solution myself:
$regex = '~^
(?=(a(?-1)?b)c)
a+(b(?-1)?c)
$~x';
var_dump(preg_match($regex, 'aabbcc')); // 1
var_dump(preg_match($regex, 'aaabbbccc')); // 1
var_dump(preg_match($regex, 'aaabbbcc')); // 0
var_dump(preg_match($regex, 'aaaccc')); // 0
var_dump(preg_match($regex, 'aabcc')); // 0
var_dump(preg_match($regex, 'abbcc')); // 0
Try it yourself: http://codepad.viper-7.com/1erq9v
Explanation
If you consider the regex without the positive lookahead assertion (the (?=...) part), you have this:
~^a+(b(?-1)?c)$~
This does nothing more than check that there's an arbitrary number of as, followed by an equal number of bs and cs.
This doesn't yet satisfy our grammar, because the number of as must be the same, too. We can ensure that by checking that the number of as equals the number of bs. And this is what the expression in the lookahead assertion does: (a(?-1)?b)c. The c is necessary so we don't only match a part of the bs.
Conclusion
I think this impressively shows that modern regex is not only capable of parsing non-regular grammars, but can even parse non-context-free grammars. Hopefully this will lay to rest the endless parroting of "you can't do X with regex because X isn't regular"
Here is an alternative solution using balancing groups with .NET regex:
^(?'a'a)+(?'b-a'b)+(?(a)(?!))(?'c-b'c)+(?(b)(?!))$
Not PCRE, but may be of interest.
Example at: http://ideone.com/szhuE
Edit: Added the missing balancing check for the group a, and an online example.
My question is: How far can you go?
In the interests of not creating code that is an unreadable morass of punctuation, I'm going to risk the downvotes and answer a different, though very much related, question: how far should you go?
Regular expression parsers are a brilliant thing to have in your toolkit but they are not the be all and end all of programming. The ability to write parsers in a readable manner is also a brilliant thing to have in your toolkit.
Regular expressions should be used right up to the point where they start making your code hard to understand. Beyond that, their value is dubious at best, damaging at worst. For this specific case, rather than using something like the hideous:
~^(?=(a(?-1)?b)c)a+(b(?-1)?c)$~x
(with apologies to NikiC), which the vast majority of people trying to maintain it are either going to have to replace totally or spend substantial time reading up on and understanding, you may want to consider something like a non-RE, "proper-parser" solution (pseudo-code):
# Match "aa...abb...bcc...c" where:
# - same character count for each letter; and
# - character count is one or more.
def matchABC (string str):
# Init string index and character counts.
index = 0
dim count['a'..'c'] = 0
# Process each character in turn.
for ch in 'a'..'c':
# Count each character in the subsequence.
while index < len(str) and str[index] == ch:
count[ch]++
index++
# Failure conditions.
if index != len(str): return false # did not finish string.
if count['a'] < 1: return false # too few a characters.
if count['a'] != count['b']: return false # inequality a and b count.
if count['a'] != count['c']: return false # inequality a and c count.
# Otherwise, it was okay.
return true
This will be far easier to maintain in the future. I always like to suggest to people that they should assume those coming after them (who have to maintain the code they write) are psychopaths who know where you live - in my case, that may be half right, I have no idea where you live :-)
Unless you have a real need for regular expressions of this kind (and sometimes there are good reasons, such as performance in interpreted languages), you should optimise for readability first.
Qtax Trick
A solution that wasn't mentioned:
^(?:a(?=a*(\1?+b)b*(\2?+c)))+\1\2$
See what matches and fails in the regex demo.
This uses self-referencing groups (an idea #Qtax used on his vertical regex).

regular expression which returns false always [duplicate]

This question already exists:
Closed 12 years ago.
Possible Duplicate:
What regular expression can never match?
how do i write a regular expression which returns false always in php.
i wanted this bcos . i wanted to display a error msg with out a form rule...so i did like this..
if($values['result_msg'] == 'ERROR')
{
$form->registerRule('just_check','regex','/$^/');
$form->addRule('abc', 'Please enter valid Model Number.','just_check');
}
There are lots of ways to do it:
/(?=a)b/
This fails to match because it searches for a character which is both a and b.
/\Zx\A/
This fails to match because the end of the string cannot come before the start of the string.
/x\by/
This fails to match because a word boundary cannot be between the characters x and y.
I don't know why you want to do this, but this'll do it:
(?!x)x
The first bit (?!..) is a negative lookahead which says "make sure this position does not match the contents of this lookahead", where the contents is x, and then the final x says "match x" - since these two are opposites, the expression will never match.
You may also want to add start/end markers, i.e.
^(?!x)x$
You can swap both the x with pretty much anything, so long as both bits are equivalent.
There are plenty of other ways to do it, basically you just put two mutually exclusive conditions next to each other for matching the same place, and the regex will fail to match - see Mark's answer for more examples.
Try this out:
$.^

Rotation in PHP's regex

How can you match the following words by PHP, either by regex/globbing/...?
Examples
INNO, heppeh, isi, pekkep, dadad, mum
My attempt would be to make a regex which has 3 parts:
1st match match [a-zA-Z]*
[a-zA-Z]?
rotation of the 1st match // Problem here!
The part 3 is the problem, since I do not know how to rotate the match.
This suggests me that regex is not the best solution here, since it is too very inefficient for long words.
I think regex are a bad solution. I'd do something with the condition like: ($word == strrev($word)).
Regexs are not suitable for finding palindromes of an arbitrary length.
However, if you are trying to find all of the palindromes in a large set of text, you could use regex to find a list of things that might be palindromes, and then filter that list to find the words that actually are palindromes.
For example, you can use a regex to find all words such that the first X characters are the reverse of the last X characters (from some small fixed value of X, like 2 or 3), and then run a secondary filter against all the matches to see if the whole word is in fact a palindrome.
In PHP once you get the string you want to check (by regex or split or whatever) you can just:
if ($string == strrev($string)) // it's a palindrome!
i think this regexp can work
$re = '~([a-z])(.?|(?R))\1~';

PHP: Simple regular expressions to match length?

I'm creating a registration system that needs to check the name/pass etc. with REGEX (and prefer to), what I've got so far is:
//Check so numbers aren't first, such as 00foobar
preg_match('/^(?!\d)[a-z0-9]+$/iD',$usrname);
//Just simple check
preg_match('/^[a-zA-Z0-9]+$/',$psword);
But I have to do stupid things in IF statements like:
if strlen($psword) > 30 || if (strlen($psword) < 4) ....
How would I impliment the length checking in my two original regular expression statements? This would make me so happy..
same but using the \w and \d for word and digits, but you might want also to include basic symbols like %!?/ ... etc...
preg_match('/^[\w\d]{4,30}$/',$psword);
the {n,v} would validate for minimum n and maximum v elements before.
like A{2,3} would validate for AA and AAA. you can take a look there for more references
On the same fashion if you want only to set the minimum of patern {n,} would do it. For example:
preg_match('/^[\w\d]{4,}$/',$psword);
I think this should do the trick:
preg_match('/^[a-zA-Z0-9]{4,30}$/',$psword);

Categories