Hi I have 3 regex preg_match in 1 if..
I want to know if it's possible to mix 3 regex in 1?
this is my if with 3 regex :
if(!preg_match("#\s#",$file) && !preg_match("#\.\.\/#",$file) && (preg_match_all("#/#",$file,$match)==1)):
(I want: no "space" , no "../" and only 1 "/")
thanks for your help.
EDIT
add the needed in list point (more readable):
no "space"
no "../"
1 "/"
It's quite simple. Let's start step by step crafting this regex:
First of all, let's use anchors to define begin&end of string: ^$
I want: no "space", we've got \S which matches a non-white space character: ^\S+$
no "../", let's add a negative lookahead ^(?!.*[.][.]/)\S+$, note that we don't need to escape the dot inside a character class. As for the forwardslash, we'll use different delimiters
one optional "/", we could add a negative lookahead that prevents 2 forwardslashes ^(?!(?:.*/){2})(?!.*[.][.]/)\S+$
Let's define the delimiters and add the s modifier to match newlines with .: ~^(?!(?:.*/){2})(?!.*[.][.]/)\S+$~s and here you go with an online demo
You can use:
if (preg_match('~^(?!.*?(?: |\.\./))(?!(.*?/){2}).*$~', $file) {
...
}
Working Demo
Why not this:
if (preg_match('~((?>[^\s/.]++|\.(?!\./))*)/?(?1)\z~A', $str))
echo 'OK';
details:
~
( # capture group 1
(?>
[^\s./]++ # all that is not a space, a dot or a slash
| # OR
\.(?!\./) # a dot not followed by another dot and a slash
)*
)
/? # optional /
(?1) # repeat the capture group 1
\z # anchor for end of the string
~A # anchored pattern
Note: if you want to exclude the empty string, two possibilities:
if (preg_match('~(?=.)((?>[^\s/.]++|\.(?!\./))*)/?(?1)\z~A', $str))
or
if (preg_match('~((?>[^\s/.]++|\.(?!\./))*)/?(?1)\z~A', $str, $m) && $m)
You cannot merge the three because you have a match_all.
I would replace preg_match_all by substr_count, because pattern is static, so it should be faster.
if(!preg_match("#\s|\.\./#",$file) && (substr_count($file,'/')<=1))
Edit: replaced ==1 by <=1 for / being optional
Edit2: We do not loose too much readability by just merging the two negative patterns
Related
Let's say I can have strings like these:
^(www.|)mysite1.com$
^(.*)mysite2.com(.*)$
^(www\.|)mysite3\.com$
How do I get only the mysite1, mysite2 or mysite3 part of such strings. I tried set the non-alphanumeric parts to empty string using:
preg_replace("/[^A-Za-z0-9]/", '', $mystring);
But that returns me
mysite1com
mysite2com
mysite3com
Thanks in advance.
What you might do is use preg_match instead of preg_replace and use for example this regex:
\^\([^)]+\)\K[A-Za-z0-9]+
That would match
\^ # Match ^
\( # Match (
[^)]+ # Match not ) one or more times
\) # Match )
\K # Reset the starting point of the reported match
[A-Za-z0-9]+ # Match one or more upper/lowercase character or digit
For example:
preg_match("/\^\([^)]+\)\K[A-Za-z0-9]+/", "^(www.|)mysite1.com$", $matches);
echo $matches[0];
Demo
With preg_replace an approach could be to use 3 capturing groups where the value you want to keep is in the second group.
In the replacement, you would use $2:
(\^\([^)]+\))([A-Za-z0-9]+)(.*)
preg_replace("/(\^\([^)]+\))([A-Za-z0-9]+)(.*)/", '$2', $mystring);
Demo
I have following sting. I wanted to know any string has two slashes or not.
$sting = "largeimg/fee0b04800e22590/myimage1.jpg";
I am trying to use the following PHP emthodl
if(preg_match("#^/([A-Za-z]|[0-9])/([A-Za-z]|[0-9]+)$#", $sting))
But it is not working properly. Please help me.
Here is how to do it in regex (see demo):
^([^/]*/){2}
Your code:
if(preg_match("#^([^/]*/){2}#", $sting)) {
// two slashes!
}
Explain Regex
^ # the beginning of the string
( # group and capture to \1 (2 times):
[^/]* # any character except: '/' (0 or more
# times (matching the most amount
# possible))
/ # '/'
){2} # end of \1 (NOTE: because you are using a
# quantifier on this capture, only the LAST
# repetition of the captured pattern will be
# stored in \1)
you could use substr_count(), do:
$sting = "largeimg/fee0b04800e22590/myimage1.jpg";
if(substr_count($sting, '/') == 2) { echo "has 2 slashes"; }
To check for 2 slashes you can use this regex:
preg_match('#/[^/]*/#', $sting)
Several other answers provide regular expressions that work but they do not explain why the expression in the question does not work. The expression is:
#^/([A-Za-z]|[0-9])/([A-Za-z]|[0-9]+)$#
The section ([A-Za-z]|[0-9]) is equivalent to ([A-Za-z0-9]). The extra + in the second similar section makes that part quite different. The + is of higher precedence than the |. Hence the section ([A-Za-z]|[0-9]+) is equivalent to ([A-Za-z]|([0-9]+)) (ignoring the difference between capturing and non-capturing brackets). The expression is interpreted as:
^ Start of string
/ The character '/'
([A-Za-z]|[0-9]) One alphanumeric
/ The character '/'
(
[A-Za-z] One alpha character
| or
[0-9]+ One or more digits
)
$ End of the string
This will only match strings where the first three characters are /, one alphanumeric, then /. Then the remainder of the string must be either one alpha or several digits. Thus these strings would be matched:
/a/b
/c/123
/4/d
/5/6
/7/890123456789
These strings would not be matched:
/aa/b
c/c/123
/44/d
/5/6a
/5/a6
/7/ee
I need to match a sequence of characters but only if it's not preceded by a "?" or "#" with 0 or more (any) number of wildcard characters in between.
$extension_regex =
'/
(?<!\?|\#) # Negative look behind not "?" or "#"
\/ # Match forward slash
[^\/\?#]+ # Has one or more of any character except forward slash, question mark and hash
\. # Dot
([^\/\?#]+) # Has one or more of any character except forward slash, question mark and hash
/iux';
Examples:
"?randomcharacters/index.php" should not get matched
"#randomcharacters/index.php" should not get matched
"randomcharacters/index.php" should get matched
I understand that the lookbehind is not working because it sees that "/index.php" is not preceded by ? or #. But I can't figure out how to add wildcard "distance" between the ? or # and the /index.php.
The Answer
Based on #Jerry's answer. Here's the full regex as the answer:
$extension_regex =
'~
^
(?:
(?!
[?#]
.*
/
[^/?#]+
\.
[^/?#]+
)
.
)*
/
[^/?#]+
\.
([^/?#]+)
~iux';
You cannot put a variable width assertion within a lookbehind in PCRE, but you could perhaps use a work around using a negative lookahead, something like this maybe?
^(?:(?![#?].*/index.php).)*(/index.php)
I added the capture group just to get the part you want to match, even though it might not be actually useful here.
regex101 demo
^(?:(?![#?].*/index.php).)* will basically match any character, as long as there's no # or ? followed by the string you want to match (/index.php) immediately ahead.
In C#, you might otherwise be able to use:
(?<![#?].*)/index.php
This may help:
$extension_regex = 'string';
$arr = array('?', '#', '0');//these are the forbidden characters
if(in_array(substr($extension_regex, 0, 1), $arr))
echo "true";
else
echo "false";
I have a string that looks like this:
[if-abc] 12345 [if-def] 67890 [/if][/if]
I have the following regex:
/\[if-([a-z0-9-]*)\]([^\[if]*?)\[\/if\]/s
This matches the inner brackets just like I want it to. However, when I replace the 67890 with text (ie. abcdef), it doesn't match it.
[if-abc] 12345 [if-def] abcdef [/if][/if]
I want to be able to match ANY characters, including line breaks, except for another opening bracket [if-.
This part doesn't work like you think it does:
[^\[if]
This will match a single character that is neither of [, i or f. Regardless of the combination. You can mimic the desired behavior using a negative lookahead though:
~\[if-([a-z0-9-]*)\]((?:(?!\[/?if).)*)\[/if\]~s
I've also included closing tags in the lookahead, as this avoid the ungreedy repetition (which is usually worse performance-wise). Plus, I've changed the delimiters, so that you don't have to escape the slash in the pattern.
So this is the interesting part ((?:(?!\[/?if).)*) explained:
( # capture the contents of the tag-pair
(?: # start a non-capturing group (the ?: are just a performance
# optimization). this group represents a single "allowed" character
(?! # negative lookahead - makes sure that the next character does not mark
# the start of either [if or [/if (the negative lookahead will cause
# the entire pattern to fail if its contents match)
\[/?if
# match [if or [/if
) # end of lookahead
. # consume/match any single character
)* # end of group - repeat 0 or more times
) # end of capturing group
Modifying a little results in:
/\[if-([a-z0-9-]+)\](.+?)(?=\[if)/s
Running it on [if-abc] 12345 [if-def] abcdef [/if][/if]
Results in a first match as: [if-abc] 12345
Your groups are: abc and 12345
And modifying even further:
/\[if-([a-z0-9-]+)\](.+?)(?=(?:\[\/?if))/s
matches both groups. Although the delimiter [/if] is not captured by either of these.
NOTE: Instead of matching the delimeters I used a lookahead ((?=)) in the regex to stop when the text ahead matches the lookahead.
Use a period to match any character.
I need a regular expression that will match any string containing at most 2 dashes and 2 dots.
There does not HAVE to be a dash nor a dot, but if there is 3+ dashes or 3 dots or even both 3+ dashes and 3+ dots, then the regex must not match the string.
Intended for use in PHP.
I know of easy alternatives using PHP functions, but it is to be used in a large system that just allows filtering using regular expressions.
Example string that will be MATCHED:
hello-world.com
Example string that will NOT be matched:
www.hello-world.easy.com or hello-world-i-win.com
Is this matching your expectations?
(?!^.*?([.-]).*\1.*\1.*$)^.*$
See it here on Regexr
(?!^.*?([.-]).*\1.*\1.*$) is a negative lookahead. It matches the first .- put it in the capture group 1, and then checks if there are two more of them using hte backreference \1. As soon as it found three, the expression will not match anymore.
^.*$ matches everything from start to the end, if the negative lookahead has not matched.
Use this: (?!^.*?([-.])(?:.*\1){2}.*$)^.*$
This tested regex will do the trick:
$re = '/# Match string with 2 or fewer dots or dashes
^ # Anchor to start of string.
(?=[^.]*(?:\.[^.]*){0,2}$) # Assert 2 or fewer dots.
(?=[^\-]*(?:-[^\-]*){0,2}$) # Assert 2 or fewer dashes.
.* # Ok to match string.
$ # Anchor to end of string.
/sx';