I'm trying to use preg_match() in PHP to make a pattern match for 4 digit numbers that have this pattern:
0033
1155
2277
Basically the first 2 digits are the same and the last 2 digits are the same, but not all 4 digits are the same.
Is preg_match() even the correct function to use? Or should I just split them up and match that way?
To search this kind of number in a text you can use:
preg_match('~\b(\d)\1(?!\1)(\d)\2\b~', $str, $m)
(or with preg_match_all if you want all of them)
details:
~ # pattern delimiter
\b # word boundary (to be sure that 1122 isn't a part of 901122)
(\d) # capture the first digit in group 1
\1 # back-reference to the group 1
(?!\1) # negative lookahead: check if the reference doesn't follow
(\d) #
\2 #
\b # word boundary (to be sure that 1122 isn't a part of 112234)
~ #
If you want to check if an entire string is the number, use the string limit anchors in place of word boundaries:
~\A(\d)\1(?!\1)(\d)\2\z~
You could use something like array_filter with a comparison callback:
function compare($number) {
// Compare first 2 numbers
if (intval($number[0]) !== intval($number[1])) {
return false;
}
// Compare last 2 numbers
if (intval($number[2]) !== intval($number[3])) {
return false;
}
// Make sure first and last numbers aren't the same
if (intval($number[0]) === intval($number[3])) {
return false;
}
return true;
}
$data = array_filter($data, 'compare');
You could also do this using a closure:
$data = array_filter($data, function($number) {
return intval($number[0]) === intval($number[1]) && intval($number[2]) === intval($number[3]) && intval($number[0]) !== intval($number[3]);
});
Examples here: http://ideone.com/0VwJz8
Related
Supposing there's an array as the following:
$arr = array('foo1234bar', 'foo1234', '1234bar', 'foo12345bar');
and I just need the elements that contains 4 characters in total only. So except for foo12345bar, other 3 elements are valid.
Because '\d{4}' would match foo12345bar, so I try following clumsily:
$arr = array('foo1234bar', 'foo1234', '1234bar', 'foo12345bar');
$result = array();
foreach ($arr as $value) {
preg_match('/\d+/', $value, $match);
if (strlen($match[0]) != 4) {
continue;
}
$result[] = $value;
}
var_dump($result); //array('foo1234bar', 'foo1234', '1234bar')
Is there a regular expression to match directly(so the if condition can be omitted)? Thank you in advance.
This easy to handle with look-around regex and preg_grep function:
$arr = array('foo1234bar', 'foo1234', '1234bar', 'foo12345bar');
print_r(preg_grep('/(?<!\d)\d{4}(?!\d)/', $arr));
RegEx Breakup:
(?<!\d) # assert previous char is not a digit
\d{4} # match exact 4 digits
(?!\d) # assert next char is not a digit
Output:
Array
(
[0] => foo1234bar
[1] => foo1234
[2] => 1234bar
)
Assuming the characters in front of and after the numbers will always be alphabetical, you can use this regex:
^[a-zA-Z]*\d{4}[a-zA-Z]+$
Modify your regex as follows
/^\D*\d{4}\D*$/
Explaination
^ your string must start with
\D any non-digit char
* repeated from 0 to infinite times
\d{4} followed by any digit repeated EXACTLY 4 times
\D followed by any non-digit char
* repeated from 0 to infinite times
$ end of the string
Moreover you could modify your code as follows
$arr = array('foo1234bar', 'foo1234', '1234bar', 'foo12345bar');
$result = array_filter(
$arr,
function($element) {
return preg_match('/^\D*\d{4}\D*$/', $element);
}
);
var_dump($result);
Pay attention
As OP didn't specify it, this regex will match even 1234 (any four digit string without non-digit chars in front or behind). If he wishes to have at least a char in front or/and behind, this regex must be changed.
the regexp will be \d{4}
preg_match('/\d{4}/', $value, $match);
expect will help
you might try folowing : preg_match('/\D\d{4}\D/', $value, $match); it searches for:
a not digit(/D)
4 digits(/d{4})
again a non digit(/D)
This regular expression will work on all your examples:
'/^\D*(\d{4})\D*$/'
││ │ │ └── end string
││ │ └───── zero or more NOT digits
││ └─────────── four digits ( match 1 )
│└─────────────── zero or more NOT digits
└──────────────── start string
They doesn't work if there are multiple number group in the string ( '123abc1234o' ).
I am trying to do a comparison of serial numbers like so 20140831-123 or 20140831-1234 so the form can accept our new serial numbers which contain 4 last numbers. So far I have tried an elseif statement and an or operator with no results what am I doing wrong? is there a way to change the reg expression itself to accept 3 or 4 digits at the end of the serial?
if($name == 'newserial1'){
$newserial1 = $_POST['newserial1'];
if($newserial1 != '') {
if(!preg_match('/^([0-9]{8}-)([0-9]{3})$/', $newserial1) ||
(!preg_match('/^([0-9]{8}-)([0-9]{4})$/', $newserial1))) {
$result['valid'] = false;
$result['reason'][$name] = 'Incorrect Serial Number.';
}
}
}
Just use the below regex to match last 3 or 4 digits also,
^([0-9]{8}-)([0-9]{3,4})$
DEMO
Explanation:
^ Asserts that we are at the start.
([0-9]{8}-) Captures 8 digits and a following - symbol.
([0-9]{3,4}) Remaining three or four digits are captured by the second group.
$ Asserts that we are at the end.
Use \d{3,4}$ to match 3 or 4 digit in the end
Here is the complete regex pattern
^(\d{8})-(\d{3,4})$
Here is online demo
Pattern explanation:
^ the beginning of the string
( group and capture to \1:
\d{8} digits (0-9) (8 times)
) end of \1
- '-'
( group and capture to \2:
\d{3,4} digits (0-9) (between 3 and 4 times)
) end of \2
$ the end of the string
Your code works fine, just remove Not operator from your if clauses, and add matches to preg_match:
if($name == 'newserial1'){
$newserial1 = $_POST['newserial1'];
if($newserial1 != '') {
if(preg_match('/^([0-9]{8}-)([0-9]{3})$/', $newserial1, $matches) ||
(preg_match('/^([0-9]{8}-)([0-9]{4})$/', $newserial1, $matches))) {
//$result['valid'] = false;
//$result['reason'][$name] = 'Incorrect Serial Number.';
$result['matches'] = $matches[2];
}
}
}
I'm using preg_match as a way to validate inputs on a form. Specifically, I am trying to validate input of currency. Here is the function:
if (preg_match("/^\$(((\d{1,3},)+\d{3})|\d+)\.\d{2}$/i", $inString)) {
return True;
} else {
return False;
}
I can get this to work AT ALL. I keeps returning False regardless of what I feed it (including valid strings). I'm sure I'm doing something obviously wrong, but I can't see it. You know how it is...
Anyone have any suggestions?
Try something like this:
$inString = '1550.50';
if (preg_match("/\b\d{1,3}(?:,?\d{3})*(?:\.\d{2})?\b/", $inString)) {
echo "True";
} else {
echo "False";
}
explanation:
\b # word boundary assertion
\d{1,3} # 1-3 digits
(?: # followed by this group...
,? # an optional comma
\d{3} # exactly three digits
)* # ...any number of times
(?: # followed by this group...
\. # a literal dot
\d{2} # exactly two digits
)? # ...zero or one times
\b # word boundary assertion
The preg_match function already returns True or False depending on whether it matches, so there is no need to return True or False a second time.
This means you can directly echo the values of True or False:
$inString = "$12.50";
$price_regex = '~^\$(((\d{1,3},)+\d{3})|\d+)\.\d{2}$~';
echo preg_match($price_regex, $inString);
// echoes 1
You can also directly return these values:
return preg_match($price_regex, $inString);
You can perform a Boolean test:
if( preg_match($price_regex, $inString) ) { // take some action }
else { // take another action }
If what you want instead is to echo some value depending on whether there is a match, do this:
echo (preg_match($price_regex, $inString)) ? "**It Matches!**" : "Nah... No match." ;
Notes:
Changed the delimiter to ~ (more legible)
Removed the i flag (there are no letters, so it doesn't need to be case-insensitive)
Both answers given before this work, but here's an explanation of why the original preg_match pattern didn't work.
It's because the pattern is enclosed in double quotes. When PHP sees this, it treats whatever follows a $ sign as a variable name. If you need to include a literal $ sign inside a double quoted string, the dollar has to be preceded by a backslash.
so both of these patterns work:
'/^\$(((\d{1,3},)+\d{3})|\d+)\.\d{2}$/i'
"/^\\$(((\d{1,3},)+\d{3})|\d+)\.\d{2}\$/i"
Obviously, using single quotes is simpler in this case.
I'm trying to get the string that match with original and with number in the end.
I got these strings:
mod_courts2
mod_courts_config
mod_courts_config2
From these strings I want the one that matches only with "mod_courts" with number in the end.
I'm doing this:
if (strpos($t, "mod_courts") !== FALSE) {
preg_match('/^\w+(\d+)$/U', $t, $match);
echo $match;
}
This returns me "mod_courts2" and "mod_courts_config2", I just want "mod_courts2"
Use the following regex:
/^[a-z]+_[a-z]+(\d+)$/
Explanation:
^ - assert position at the beginning of the string
[a-z]+ - match any alphabet one or more times
_ - match a literal undescore character
[a-z]+ - match any alphabet one or more times
(\d+) - match (and capture) any digit from 0 to 9 one or more times
$ - assert position at the end of the string
Test cases:
$array = array(
'mod_courts2',
'mod_courts_config',
'mod_courts_config2'
);
foreach ($array as $string) {
if(preg_match('/^[a-z]+_[a-z]+(\d+)$/i', $string, $matches)) {
print_r($matches);
}
}
Output:
Array
(
[0] => mod_courts2
[1] => 2
)
Very simply, you can do:
/^(mod_courts\d+)$/
However, if you want exactly the following format: sometext_somettext2, you can use the following regex:
/^([a-zA-Z]+_[a-zA-Z]+\d+)$/
or
/^([^_]+_[^_]+\d+)$/
Demos
http://regex101.com/r/jP8iC1
http://regex101.com/r/tI1uX8
http://regex101.com/r/fX8pO5
^mod_courts\d+$
this should do it
You can just use
^mod_courts[0-9]+$
Meaning mod_courts followed by a number (and only that, thanks to ^$ matching the beginning and end of the string). No need for the strpos check.
I want to create a regular expression in PHP, which will allow to user to enter a phone number in either of the formats below.
345-234 898
345 234-898
235-123-456
548 812 346
The minimum length of number should be 7 and maximum length should be 12.
The problem is that, the regular expression doesn't care about the minimum and maximum length. I don't know what is the problem in it. Please help me to solve it. Here is the regular expression.
if (preg_match("/^([0-9]+((\s?|-?)[0-9]+)*){7,12}$/", $string)) {
echo "ok";
} else {
echo "not ok";
}
Thanks for reading my question. I will wait for responses.
You should use the start (^) and the end ($) sign on your pattern
$subject = "123456789";
$pattern = '/^[0-9]{7,9}$/i';
if(preg_match($pattern, $subject)){
echo 'matched';
}else{
echo 'not matched';
}
You can use preg_replace to strip out non-digit symbols and check length of resulting string.
$onlyDigits = preg_replace('/\\D/', '', $string);
$length = strlen($onlyDigits);
if ($length < 7 OR $length > 12)
echo "not ok";
else
echo "ok";
Simply do this:
if (preg_match("/^\d{3}[ -]\d{3}[ -]\d{3}$/", $string)) {
Here \d means any digits from 0-9. Also [ -] means either a space or a hyphen
You can check the length with a lookahead assertion (?=...) at the begining of the pattern:
/^(?=.{7,12}$)[0-9]+(?:[\s-]?[0-9]+)*$/
Breaking down your original regex, it can read like the following:
^ # start of input
(
[0-9]+ # any number, 1 or more times
(
(\s?|-?) # a space, or a dash.. maybe
[0-9]+ # any number, 1 or more times
)* # repeat group 0 or more times
)
{7,12} # repeat full group 7 to 12 times
$ # end of input
So, basically, you're allowing "any number, 1 or more times" followed by a group of "any number 1 or more times, 0 or more times" repeat "7 to 12 times" - which kind of kills your length check.
You could take a more restricted approach and write out each individual number block:
(
\d{3} # any 3 numbers
(?:[ ]+|-)? # any (optional) spaces or a hyphen
\d{3} # any 3 numbers
(?:[ ]+|-)? # any (optional) spaces or a hyphen
\d{3} # any 3 numbers
)
Simplified:
if (preg_match('/^(\d{3}(?:[ ]+|-)?\d{3}(?:[ ]+|-)?\d{3})$/', $string)) {
If you want to restrict the separators to be only a single space or a hyphen, you can update the regex to use [ -] instead of (?:[ ]+|-); if you want this to be "optional" (i.e. there can be no separator between number groups), add in a ? to the end of each.
if (preg_match('/^(\d{3}[ -]\d{3}[ -]\d{3})$/', $string)) {
may it help you out.
Validator::extend('price', function ($attribute, $value, $args) {
return preg_match('/^\d{0,8}(\.\d{1,2})?$/', $value);
});