I would like to create a validate function for numbers only, actually I have those ones that works fine, and I tried to create one myself, but it's unfortunately not working. Here are the alphanumeric and others working fine :
// Validators
private function custom($validator, $value)
{
return call_user_func($validator, $value, $this->request, $this->id);
}
private function alphanumeric($value, $custom)
{
return preg_match('/^(['.$custom.'a-z0-9_]*)$/i', $value);
}
private function valid_email($value)
{
return preg_match('/^\S+#\S+\.\S+$/', $value);
}
And the one I tried to create by modifying the alphanumeric one :
private function numbers_only($value, $custom)
{
return preg_match('/^(['.$custom.'0-9_]*)$/i', $value);
}
What's wrong with this one ?
EDIT :
I also have a JS helping with the form, for alphanumeric it's :
Form.prototype.alphanumeric = function(value, custom)
{
return !value.replace(new RegExp('['+custom+'a-z0-9_]', 'ig'), '').length;
};
What would be the JS for numeric only ?
Use
is_numeric($value);
return is true or false
If you want only numbers, remove the $custom part from the function. The /i implies case-insensitive matching, which is not relevant for numeric matches, and so can be removed.
private function numbers_only($value)
{
return preg_match('/^([0-9]*)$/', $value);
}
The expression above will match zero or more numbers, so blank input is allowed. To require at least one number, change * to + as in
return preg_match('/^([0-9]+)$/', $value);
And the [0-9]+ can be abbreviated as \d+. Since you are not capturing the value inside a an array of matches, there is no need for the extra overhead which is added by including the () capture group. That can be omitted as well.
return preg_match('/^\d+$/', $value);
Or skip the regex entirely...
Finally, if you've gotten this far and are matching only integers, it is far easier and less resource-intensive to just do:
// If you really intend to match numbers only, and not all numeric values
// which might include .,
function numbers_only($value)
{
return ctype_digit(strval($value));
}
In PHP, for a "only numbers" validation you can use different approaches:
is_int or is_integer
is_numeric
regular expressions
ctype_digit
filter_var
is_integer()
for this function these values are are not valid: "0010", "123"
is_numeric()
for this function these values are valid: 1.3, +1234e44 and 0x539
filter_var()
for this function a value as "00123" is not valid
CONSLUSION
it seems that only regex and ctype_digit work always fine.
TEST
a simple test here
Related
I have a function which will return true if input is pure numeric or alphabate else it will return false. This function is working fine.
function checktype($a)
{
if (preg_match('/^\d+$/', $a)) { //check numeric (can use other numeric regex also like /^[0-9]+$/ etc)
$return = true;
} else if (preg_match('/^[a-zA-Z]+$/', $a)) { //check alphabates
$return = true;
} else { //others
$return = false;
}
return $return;
}
var_dump(checktype('abcdfekjh')); //bool(true)
var_dump(checktype('1324654')); //bool(true)
var_dump(checktype('1324654hkjhkjh'));//bool(false)
No I tried to optimized this function by removing conditions so I modified code to:
function checktype($a)
{
$return = (preg_match('/^\d+$/', $a) || preg_match('/^[a-zA-Z]+$/', $a)) ? true:false;
return $return;
}
var_dump(checktype('abcdfekjh')); //bool(true)
var_dump(checktype('1324654')); //bool(true)
var_dump(checktype('1324654hkjhkjh'));//bool(false)
Now in third step I tried to merge both regex in single regex so I can avoid two preg_match function and got stuck here:
function checktype($a)
{
return (preg_match('regex to check either numeric or alphabates', $a)) ? true:false;
}
I tried a lot of combinations since 2 days by using OR(!) operator using not operator(?!) but no success at all.
Below some reference website from which i pick expression and made some combinations:
http://regexlib.com/UserPatterns.aspx?authorid=26c277f9-61b2-4bf5-bb70-106880138842
http://www.rexegg.com/regex-conditionals.html
OR condition in Regex
Regex not operator (come to know about NOT operator)
https://www.google.co.in/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=regular+expression+not+condition (come to know about NOT operator)
So here main question is, is there any single regex pattern to check string contains pure numeric value or pure alphabates?
Note: Alternative solution can be check string is alphanumeric and then return true or false accordingly. Also php inbuilt function like is_numeric and is_string can be used, but I am more curious to know the single regex pattern to check weather string conains pure numeric digit or pure alphaba digits.
A one regex to check if a string is all ASCII digits or all ASCII letters is
'/^(?:\d+|[a-zA-Z]+)$/'
See regex demo
This regex has two things your regexps do not have:
a grouping construct (?:....)
an alternation operator |.
Explanation:
^ - start of string
(?:\d+ - one or more digits
| - or...
[a-zA-Z]+) - one or more ASCII letters
$ - end of string
If you need to make it Unicode-aware, use [\p{L}\p{M}] instead of [a-zA-Z] (and \p{N} instead of \d, but not necessary) and use the /u modifier:
'/^(?:\p{N}+|[\p{L}\p{M}]+)$/u'
And in case you want to really check that from the beginning to end, use
'/\A(?:\p{N}+|[\p{L}\p{M}]+)\z/u'
^^ ^^
or
'/^(?:\p{N}+|[\p{L}\p{M}]+)$/Du'
The $ without /D modifier does not match the string at its "very end", it also matches if there is a newline after it as the last character.
I am specifically targeting numerical only, So if I am using a phone mask using javascript on front end that filters user input to (000)000-000, basically [2-9] and [0-9] as mask (jquery.maskedinput-1.3.js) and mobile filter...
jQuery(function ($e) {
var isMobile = navigator.userAgent.match(/(iPhone|iPod|iPad|Android|BlackBerry)/);
$e('#refer').val(window.location.href);
if (!(isMobile)) {
$e('#phone').mask('(299)299-9999');
$e('#field_phone_number').mask('299-299-9999');
}
});
For server side I have a regular expression in PHP as (nothing special yet)
function phonenumber($value)
{
return preg_match("/\(?\b[(. ]?[0-9]{3}\)?[). ]?[0-9]{3}[-. ]?[0-9]{4}\b/i", $value);
}
How can a create a regex or php script that targets all numerical values without creating a very long regex for each character? I just want to know if someone types in (222)222-2222, they get a false on the return.
function phonenumber($value)
{
$prefix = '\d{3}'; // You might want to specify '2\d\d' (200 to 299)
$regex = '#^(\('.$prefix.'\)|'.$prefix.')[\s\.-]?\d{3}[\.-]?\d{4}$#';
if (preg_match($regex, $value))
{
// Number is in a suitable format
// Now extract digits -- remove this section to not test repeated pattern
$digits = preg_replace('#[^\d]+#', '', $value);
// All numbers equal are rejected
if (preg_match('#^(\d)\1{9}$#', $digits))
return false;
// end of pattern check
// Otherwise it is accepted
return true;
}
return false; // Not in a recognized format
}
This will accept (299)423-1234 and 277-111-2222, and also (400)1234567 or 4001234567. It will reject (400-1234567 and 400-12-34-56-7. It will also reject (222)222-2222 because of the repeated 2's.
You can use a backreference \1 to detect recurring patterns. In your case you can simply mix in a .* to ignore in-between fillers like ( and -
/(\d)(.*\1){7}/
Will look for a number, and at least 7 repetitions of the same, ignoring any other characters used as filler. This will not ensure that they are consecutive however, so (222)222-8222 would match too.
Is it possible to execute a php command e.g. strtolower() through preg_replace()?
I would like to make just a party of a array in lower case letters and the other part into uppercase. The problem is that the letters are dynamically changing and are not fixed, just one word stays the same but the rest not.
e.g.
arraypart1 (should stay uppercase) (constantword)+arraypart2 (both should change to lower case letters)
arraypart2 is also changing in size of character numbers.
It's not 100% clear what you want to do, but I think it's the following: extract words from a string and lowercase/uppercase some of them according to their presence in one of arrays. preg_replace_callback will help you.
PHP 5.3 and higher:
$initial = "Mary had a little lamb";
$toupper = array("Mary", "lamb");
$tolower = array("had", "any");
$out = preg_replace_callback(
"/\b(?P<word>\w+)\b/", // for every found word
function($matches) use ($toupper, $tolower) { // call this function
if (in_array($toupper, $matches['word'])) // is this word in toupper array?
return strtoupper($matches['word']);
if (in_array($tolower, $matches['word'])) // is this word in tolower array?
return strtolower($matches['word']);
// ... any other logic
return $matches['word']; // if nothing was returned before, return original word
},
$initial);
print $out; // "MARY had a little LAMB"
If you have other arrays that need to be taken in account, put them in use statement so that they are available inside anonymous function.
PHP >= 4.0.5:
$initial = "Mary had a little lamb";
$toupper = array("Mary", "lamb");
$tolower = array("had", "any");
function replace_callback($matches) {
global $tolower, $toupper;
if (in_array($toupper, $matches['word'])) // is this word in toupper array?
return strtoupper($matches['word']);
if (in_array($tolower, $matches['word'])) // is this word in tolower array?
return strtolower($matches['word']);
// ... any other logic
return $matches['word']; // if nothing was returned before, return original word
}
$out = preg_replace_callback(
"/\b(?P<word>\w+)\b/", // for every found word
'replace_callback', // call this function
$initial);
print $out; // "MARY had a little LAMB"
As you see, nothing changed significantly, I just replaced anonymous function with a named one. To provide it with other arrays of strings, refer to them with global keyword.
I hope I understand you correctly ,preg_replace is a function and like all other functions you can do:
preg_replace(strtolower($val),$pattern,$someString);
preg_replace would be called with the lowercase version of $val
I recently found out that a method I've been using for validating user input accepts some values I'm not particularly happy with. I need it to only accept natural numbers (1, 2, 3, etc.) without non-digit characters.
My method looks like this:
function is_natural($str)
{
return preg_match('/[^0-9]+$/', $str) ? false : $str;
}
So it's supposed to return false if it finds anything else but a whole natural number. Problem is, it accepts strings like "2.3" and even "2.3,2.2"
perhaps you can clarify the difference between a "number" and a "digit" ??
Anyways, you can use
if (preg_match('/^[0-9]+$/', $str)) {
// contains only 0-9
} else {
// contains other stuff
}
or you can use
$str = (string) $str;
ctype_digit($str);
The problem with /^[0-9]+$/ is that it also accepts values like 0123.
The correct regular expression is /^[1-9][0-9]*$/.
ctype_digit() suffers the same problem.
If you also need to include zero use this regex instead: /^(?:0|[1-9][0-9]*)$/
Use ctype_digit() instead
I got an issue with ctype_digit when invoice numbers like "000000196" had to go through ctype_digit.
So I have used a:
if (preg_match('/^[1-9][0-9]?$/', $str)) {
// only integers
} else {
// string
}
I am trying to validate a Youtube URL using regex:
preg_match('~http://youtube.com/watch\?v=[a-zA-Z0-9-]+~', $videoLink)
It kind of works, but it can match URL's that are malformed. For example, this will match ok:
http://www.youtube.com/watch?v=Zu4WXiPRek
But so will this:
http://www.youtube.com/watch?v=Zu4WX£&P!ek
And this wont:
http://www.youtube.com/watch?v=!Zu4WX£&P4ek
I think it's because of the + operator. It's matching what seems to be the first character after v=, when it needs to try and match everything behind v= with [a-zA-Z0-9-]. Any help is appreciated, thanks.
To provide an alternative that is larger and much less elegant than a regex, but works with PHP's native URL parsing functions so it might be a bit more reliable in the long run:
$url = "http://www.youtube.com/watch?v=Zu4WXiPRek";
$query_string = parse_url($url, PHP_URL_QUERY); // v=Zu4WXiPRek
$query_string_parsed = array();
parse_str($query_string, $query_string_parsed); // an array with all GET params
echo($query_string_parsed["v"]); // Will output Zu4WXiPRek that you can then
// validate for [a-zA-Z0-9] using a regex
The problem is that you are not requiring any particular number of characters in the v= part of the URL. So, for instance, checking
http://www.youtube.com/watch?v=Zu4WX£&P!ek
will match
http://www.youtube.com/watch?v=Zu4WX
and therefore return true. You need to either specify the number of characters you need in the v= part:
preg_match('~http://youtube.com/watch\?v=[a-zA-Z0-9-]{10}~', $videoLink)
or specify that the group [a-zA-Z0-9-] must be the last part of the string:
preg_match('~http://youtube.com/watch\?v=[a-zA-Z0-9-]+$~', $videoLink)
Your other example
http://www.youtube.com/watch?v=!Zu4WX£&P4ek
does not match, because the + sign requires that at least one character must match [a-zA-Z0-9-].
Short answer:
preg_match('%(http://www.youtube.com/watch\?v=(?:[a-zA-Z0-9-])+)(?:[&"\'\s])%', $videoLink)
There are a few assumptions made here, so let me explain:
I added a capturing group ( ... ) around the entire http://www.youtube.com/watch?v=blah part of the link, so that we can say "I want get the whole validated link up to and including the ?v=movieHash"
I added the non-capturing group (?: ... ) around your character set [a-zA-Z0-9-] and left the + sign outside of that. This will allow us to match all allowable characters up to a certain point.
Most importantly, you need to tell it how you expect your link to terminate. I'm taking a guess for you with (?:[&"\'\s])
?) Will it be in html format (e.g. anchor tag) ? If so, the link in href will obviously end with a " or '.
?) Or maybe there's more to the query string, so there would be an & after the value of v.
?) Maybe there's a space or line break after the end of the link \s.
The important piece is that you can get much more accurate results if you know what's surrounding what you are searching for, as is the case with many regular expressions.
This non-capturing group (in which I'm making assumptions for you) will take a stab at finding and ignoring all the extra junk after what you care about (the ?v=awesomeMovieHash).
Results:
http://www.youtube.com/watch?v=Zu4WXiPRek
- Group 1 contains the http://www.youtube.com/watch?v=Zu4WXiPRek
http://www.youtube.com/watch?v=Zu4WX&a=b
- Group 1 contains http://www.youtube.com/watch?v=Zu4WX
http://www.youtube.com/watch?v=!Zu4WX£&P4ek
- No match
a href="http://www.youtube.com/watch?v=Zu4WX&size=large"
- Group 1 contains http://www.youtube.com/watch?v=Zu4WX
http://www.youtube.com/watch?v=Zu4WX£&P!ek
- No match
The "v=..." blob is not guaranteed to be the first parameter in the query part of the URL. I'd recommend using PHP's parse_url() function to break the URL into its component parts. You can also reassemble a pristine URL if someone began the string with "https://" or simply used "youtube.com" instead of "www.youtube.com", etc.
function get_youtube_vidid ($url) {
$vidid = false;
$valid_schemes = array ('http', 'https');
$valid_hosts = array ('www.youtube.com', 'youtube.com');
$valid_paths = array ('/watch');
$bits = parse_url ($url);
if (! is_array ($bits)) {
return false;
}
if (! (array_key_exists ('scheme', $bits)
and array_key_exists ('host', $bits)
and array_key_exists ('path', $bits)
and array_key_exists ('query', $bits))) {
return false;
}
if (! in_array ($bits['scheme'], $valid_schemes)) {
return false;
}
if (! in_array ($bits['host'], $valid_hosts)) {
return false;
}
if (! in_array ($bits['path'], $valid_paths)) {
return false;
}
$querypairs = explode ('&', $bits['query']);
if (count ($querypairs) < 1) {
return false;
}
foreach ($querypairs as $querypair) {
list ($key, $value) = explode ('=', $querypair);
if ($key == 'v') {
if (preg_match ('/^[a-zA-Z0-9\-_]+$/', $value)) {
# Set the return value
$vidid = $value;
}
}
}
return $vidid;
}
Following regex will match any youtube link:
$pattern='#(((http(s)?://(www\.)?)|(www\.)|\s)(youtu\.be|youtube\.com)/(embed/|v/|watch(\?v=|\?.+&v=|/))?([a-zA-Z0-9._\/~#&=;%+?-\!]+))#si';