Simple regex to match some characters and exclude others - php

I need a regex for preg_match to accept all alphanumeric characters except l, L, v, V, 0, 2.
I've tried
^[a-zA-Z0-9][^lLvV02]*$
It works good excluding lLvV02 but it also accept other characters like SPACE,ù,#,#, etc...
How should I change it?

You may use
^(?:(?![lLvV02])[a-zA-Z0-9])*$
Details
^ - start of string
(?: - start of a non-capturing group
(?![lLvV02])[a-zA-Z0-9] - an alnum char that is not one of the chars inside the character class residing inside a negative lookahead
)* - end of the non-capturing group, 0 or more repetitions
$ - end of string
See the Regulex graph:

I know you asked for a Regex, but you can test for alphanumeric first and only if that passes check that the others are NOT present:
if(ctype_alnum($string) && !preg_match('/[lLvV02]/', $string)) {
//pass
} else {
//fail
}
Or possibly substitute preg_match('/^[^lLvV02]+$/', $string).

Easiest would probably be: ^[a-km-uw-zA-KM-UW-Z13-9]*$.
I'm not saying that it's pretty but it does what it's supposed to.

Related

How to capture all phrases which doesn't have a pattern in the middle of theirself?

I want to capture all strings that doesn't have the pattern _ a[a-z]* _ in the specified position in the example below:
<?php
$myStrings = array(
"123-456",
"123-7-456",
"123-Apple-456",
"123-0-456",
"123-Alphabet-456"
);
foreach($myStrings as $myStr){
echo var_dump(
preg_match("/123-(?!a[a-z]*)-456/i", $myStr)
);
}
?>
You can check the following solution at this Regex101 share link.
^(123-(?:(?![aA][a-zA-Z]*).*)-456)|(123-456)$
It uses regex non-capturing group (?:) and regex negative lookahead (?!) to find all inner sections that do not start with 'a' (or 'A') and any letters after that. Also, the case with no inner section (123-456) is added (with the | sign) as a 2nd alternative for a wrong pattern.
A lookahead is a zero-length assertion. The middle part also needs to be consumed to meet 456. For consuming use e.g. \w+- for one or more word characters and hyphen inside an optional group that starts with your lookahead condition. See this regex101 demo (i flag for caseless matching).
Further for searching an array preg_grep can be used (see php demo at tio.run).
preg_grep('~^123-(?:(?!a[a-z]*-)\w+-)?456$~i', $myStrings);
There is also an invert option: PREG_GREP_INVERT. If you don't need to check for start and end a more simple pattern like -a[a-z]*- without lookahead could be used (another php demo).
Match the pattern and invert the result:
!preg_match('/a[a-z]*/i', $yourStr);
Don't try to do everything with a regex when programming languages exist to do the job.
You are not getting a match because in the pattern 123-(?!a[a-z]*)-456 the lookahead assertion (?!a[a-z]*) is always true because after matching the first - it has to directly match another hyphen like the pattern actually 123--456
If you move the last hyphen inside the lookahead like 123-(?!a[a-z]*-)456 you only get 1 match for 123-456 because you are actually not matching the middle part of the string.
Another option with php can be to consume the part that you don't want, and then use SKIP FAIL
^123-(?:a[a-z]*-(*SKIP)(*F)|\w+-)?456$
Explanation
^ Start of string
123- Match literally
(?: Non capture group for the alternation
a[a-z]*-(*SKIP)(*F) Match a, then optional chars a-z, then match - and skip the match
| Or
\w+- Match 1+ word chars followed by -
)? Close the non capture group and make it optional to also match when there is no middle part
456 Match literally
$ End of string
Regex demo
Example
$myStrings = array(
"123-456",
"123-7-456",
"123-Apple-456",
"123-0-456",
"123-Alphabet-456",
"123-b-456"
);
foreach($myStrings as $myStr) {
if (preg_match("/^123-(?:a[a-z]*-(*SKIP)(*F)|\w+-)?456$/i", $myStr, $match)) {
echo "Match for $match[0]" . PHP_EOL;
} else {
echo "No match for $myStr" . PHP_EOL;
}
}
Output
Match for 123-456
Match for 123-7-456
No match for 123-Apple-456
Match for 123-0-456
No match for 123-Alphabet-456
Match for 123-b-456

Regular expression alphanumeric with dash and underscore and space, but not at the beginning or at the end of the string [duplicate]

I want to design an expression for not allowing whitespace at the beginning and at the end of a string, but allowing in the middle of the string.
The regex I've tried is this:
\^[^\s][a-z\sA-Z\s0-9\s-()][^\s$]\
This should work:
^[^\s]+(\s+[^\s]+)*$
If you want to include character restrictions:
^[-a-zA-Z0-9-()]+(\s+[-a-zA-Z0-9-()]+)*$
Explanation:
the starting ^ and ending $ denotes the string.
considering the first regex I gave, [^\s]+ means at least one not whitespace and \s+ means at least one white space. Note also that parentheses () groups together the second and third fragments and * at the end means zero or more of this group.
So, if you take a look, the expression is: begins with at least one non whitespace and ends with any number of groups of at least one whitespace followed by at least one non whitespace.
For example if the input is 'A' then it matches, because it matches with the begins with at least one non whitespace condition. The input 'AA' matches for the same reason. The input 'A A' matches also because the first A matches for the at least one not whitespace condition, then the ' A' matches for the any number of groups of at least one whitespace followed by at least one non whitespace.
' A' does not match because the begins with at least one non whitespace condition is not satisfied. 'A ' does not matches because the ends with any number of groups of at least one whitespace followed by at least one non whitespace condition is not satisfied.
If you want to restrict which characters to accept at the beginning and end, see the second regex. I have allowed a-z, A-Z, 0-9 and () at beginning and end. Only these are allowed.
Regex playground: http://www.regexr.com/
This RegEx will allow neither white-space at the beginning nor at the end of your string/word.
^[^\s].+[^\s]$
Any string that doesn't begin or end with a white-space will be matched.
Explanation:
^ denotes the beginning of the string.
\s denotes white-spaces and so [^\s] denotes NOT white-space. You could alternatively use \S to denote the same.
. denotes any character expect line break.
+ is a quantifier which denote - one or more times. That means, the character which + follows can be repeated on or more times.
You can use this as RegEx cheat sheet.
In cases when you have a specific pattern, say, ^[a-zA-Z0-9\s()-]+$, that you want to adjust so that spaces at the start and end were not allowed, you may use lookaheads anchored at the pattern start:
^(?!\s)(?![\s\S]*\s$)[a-zA-Z0-9\s()-]+$
^^^^^^^^^^^^^^^^^^^^
Here,
(?!\s) - a negative lookahead that fails the match if (since it is after ^) immediately at the start of string there is a whitespace char
(?![\s\S]*\s$) - a negative lookahead that fails the match if, (since it is also executed after ^, the previous pattern is a lookaround that is not a consuming pattern) immediately at the start of string, there are any 0+ chars as many as possible ([\s\S]*, equal to [^]*) followed with a whitespace char at the end of string ($).
In JS, you may use the following equivalent regex declarations:
var regex = /^(?!\s)(?![\s\S]*\s$)[a-zA-Z0-9\s()-]+$/
var regex = /^(?!\s)(?![^]*\s$)[a-zA-Z0-9\s()-]+$/
var regex = new RegExp("^(?!\\s)(?![^]*\\s$)[a-zA-Z0-9\\s()-]+$")
var regex = new RegExp(String.raw`^(?!\s)(?![^]*\s$)[a-zA-Z0-9\s()-]+$`)
If you know there are no linebreaks, [\s\S] and [^] may be replaced with .:
var regex = /^(?!\s)(?!.*\s$)[a-zA-Z0-9\s()-]+$/
See the regex demo.
JS demo:
var strs = ['a b c', ' a b b', 'a b c '];
var regex = /^(?!\s)(?![\s\S]*\s$)[a-zA-Z0-9\s()-]+$/;
for (var i=0; i<strs.length; i++){
console.log('"',strs[i], '"=>', regex.test(strs[i]))
}
if the string must be at least 1 character long, if newlines are allowed in the middle together with any other characters and the first+last character can really be anyhing except whitespace (including ##$!...), then you are looking for:
^\S$|^\S[\s\S]*\S$
explanation and unit tests: https://regex101.com/r/uT8zU0
This worked for me:
^[^\s].+[a-zA-Z]+[a-zA-Z]+$
Hope it helps.
How about:
^\S.+\S$
This will match any string that doesn't begin or end with any kind of space.
^[^\s].+[^\s]$
That's it!!!! it allows any string that contains any caracter (a part from \n) without whitespace at the beginning or end; in case you want \n in the middle there is an option s that you have to replace .+ by [.\n]+
pattern="^[^\s]+[-a-zA-Z\s]+([-a-zA-Z]+)*$"
This will help you accept only characters and wont allow spaces at the start nor whitespaces.
This is the regex for no white space at the begining nor at the end but only one between. Also works without a 3 character limit :
\^([^\s]*[A-Za-z0-9]\s{0,1})[^\s]*$\ - just remove {0,1} and add * in order to have limitless space between.
As a modification of #Aprillion's answer, I prefer:
^\S$|^\S[ \S]*\S$
It will not match a space at the beginning, end, or both.
It matches any number of spaces between a non-whitespace character at the beginning and end of a string.
It also matches only a single non-whitespace character (unlike many of the answers here).
It will not match any newline (\n), \r, \t, \f, nor \v in the string (unlike Aprillion's answer). I realize this isn't explicit to the question, but it's a useful distinction.
Letters and numbers divided only by one space. Also, no spaces allowed at beginning and end.
/^[a-z0-9]+( [a-z0-9]+)*$/gi
I found a reliable way to do this is just to specify what you do want to allow for the first character and check the other characters as normal e.g. in JavaScript:
RegExp("^[a-zA-Z][a-zA-Z- ]*$")
So that expression accepts only a single letter at the start, and then any number of letters, hyphens or spaces thereafter.
use /^[^\s].([A-Za-z]+\s)*[A-Za-z]+$/. this one. it only accept one space between words and no more space at beginning and end
If we do not have to make a specific class of valid character set (Going to accept any language character), and we just going to prevent spaces from Start & End, The must simple can be this pattern:
/^(?! ).*[^ ]$/
Try on HTML Input:
input:invalid {box-shadow:0 0 0 4px red}
/* Note: ^ and $ removed from pattern. Because HTML Input already use the pattern from First to End by itself. */
<input pattern="(?! ).*[^ ]">
Explaination
^ Start of
(?!...) (Negative lookahead) Not equal to ... > for next set
Just Space / \s (Space & Tabs & Next line chars)
(?! ) Do not accept any space in first of next set (.*)
. Any character (Execpt \n\r linebreaks)
* Zero or more (Length of the set)
[^ ] Set/Class of Any character expect space
$ End of
Try it live: https://regexr.com/6e1o4
^[^0-9 ]{1}([a-zA-Z]+\s{1})+[a-zA-Z]+$
-for No more than one whitespaces in between , No spaces in first and last.
^[^0-9 ]{1}([a-zA-Z ])+[a-zA-Z]+$
-for more than one whitespaces in between , No spaces in first and last.
Other answers introduce a limit on the length of the match. This can be avoided using Negative lookaheads and lookbehinds:
^(?!\s)([a-zA-Z0-9\s])*?(?<!\s)$
This starts by checking that the first character is not whitespace ^(?!\s). It then captures the characters you want a-zA-Z0-9\s non greedily (*?), and ends by checking that the character before $ (end of string/line) is not \s.
Check that lookaheads/lookbehinds are supported in your platform/browser.
Here you go,
\b^[^\s][a-zA-Z0-9]*\s+[a-zA-Z0-9]*\b
\b refers to word boundary
\s+ means allowing white-space one or more at the middle.
(^(\s)+|(\s)+$)
This expression will match the first and last spaces of the article..

Creating a regular expression that will match requirements in a string

The issue
I need to write a regular expression that will match the following requirements in a string with the structure {A/B}.
Requirements/Conditions:
A and B can only be exactly one of [UGWRB].
A structure where U or G do not appear is invalid.
A structure where both characters are equal is invalid.
U or G must appear in the combination at least once.
The structure can repeat or continue infinite times, as long as each following instance is still valid when read alone. (see valid matches below)
Valid matches:
{U/G}{U/G}{U/G}
{W/G}{U/B}
{U/G}{U/B}
{U/G}
{G/U}
{U/B}
...
Invalid matches:
{U/U}{U/U}
{U/U}{G/G}
{U/G}{U/U}
{U/G}{R/B}
{G/G}
{R/B}
{W/R}
{B/W}
...
My attempt
This is what I have gotten so far, but out of all the combinations of UGWRB, I'm only getting 8 matches out of 14.
{([UG])(?(1)|\w)\/(?(1)\w|[UG])}
You have to work with lookaheads both negative and positive in order to accomplish the task:
^(?:{(?=[^{}]*[UG])([UGWRB])\/(?!\1)(?1)})+$
See live demo here
Note that m flag should be set.
Regex breakdown:
^ Match start of input string
(?: Start of non-capturing group
{ Match { literally
(?= Start of positive lookahead
[^{}]*[UG] Look for [UG] in combination
) End of lookahead
([UGWRB]) Match and capture a letter from character class
\/(?!\1)(?1) Match / and see if next char is not the same as recently captured one
} Match } literally
)+ End of group, repeat at least once
$ Match end of input string
Try this regex:
^(?!.*{([UGWRB])\/\1})(?:{(?(?=[UG]).\/[UGWRB]|[WRB]\/[UG])})+$
Click for Demo
Explanation:
^ - matches the start of the string
(?!.*{([UGWRB])\/\1}) - negative lookahead to make sure that the structures like {G/G} or {U/U} or {R/R} are not present anywhere in the string
{ - matches {
(?(?=[UG]).\/[UGWRB]|[WRB]\/[UG]) - Regex Conditional. If the current position is followed by either U or G, then the match that character followed by / and the character class [UGWRB]. Otherwise, match the character class [WRB] followed by / followed by U or G
} - matches }
+ - matches 1+ occurrences of the above sub-sequence (?:{(?(?=[UG]).\/[UGWRB]|[WRB]\/[UG])})
$ - matches the end of the string

How can I check a string's pattern with given conditions (php/regex)

This is what I'm trying to do,
$line = "dsfsdf";
if (!preg_match('/^(?=.{1,30}$)[a-zA-Z0-9\-\_]*$^/', $line))
{
echo 'No Match found';
}
else
{
echo 'Match found';
}
The requirement is below,
it can have characters
it can have numbers
As special character, it can have only hyphen (-) and underscore (_) characters in it
I'm not so good at regex part. Can someone guide me how to achieve it with a simple explanation?
You must remove ^ (start of string anchor) at the end. Also, you may replace [a-zA-Z0-9_] with \w, as without any modifiers, they are equal.
The (?=.{1,30}$) lookahead makes the regex engine only match strings with 1 to 30 characters. You may remove the lookahead and just apply the limiting quantifier to your character class.
You may use
'/^[\w-]{1,30}$/'
If you prefer a more verbose way use
'/^[a-zA-Z0-9_-]{1,30}$/'
See the PHP demo.
Both mean:
^ - start of string
[\w-]{1,30} - 1 to 30 letters/digits/underscores/- symbols
$ - end of string. NOTE that to match at the very end of the string, you need to use a D modifier, or replace $ with \z anchor (i.e. use '/^[\w-]{1,30}$/D' or '/^[\w-]{1,30}\z/' then).

Regex: how to match any string until whitespace, or until punctuation followed by whitespace?

I'm trying to write a regular expression which will find URLs in a plain-text string, so that I can wrap them with anchor tags. I know there are expressions already available for this, but I want to create my own, mostly because I want to know how it works.
Since it's not going to break anything if my regex fails, my plan is to write something fairly simple. So far that means: 1) match "www" or "http" at the start of a word 2) keep matching until the word ends.
I can do that, AFAICT. I have this: \b(http|www).?[^\s]+
Which works on foo www.example.com bar http://www.example.com etc.
The problem is that if I give it foo www.example.com, http://www.example.com it thinks that the comma is a part of the URL.
So, if I am to use one expression to do this, I need to change "...and stop when you see whitespace" to "...and stop when you see whitespace or a piece of punctuation right before whitespace". This is what I'm not sure how to do.
At the moment, a solution I'm thinking of running with is just adding another test – matching the URL, and then on the next line moving any sneaky punctuation. This just isn't as elegant.
Note: I am writing this in PHP.
Aside: why does replacing \s with \b in the expression above not seem to work?
ETA:
Thanks everyone!
This is what I eventually ended up with, based on Explosion Pills's advice:
function add_links( $string ) {
function replace( $arr ) {
if ( strncmp( "http", $arr[1], 4) == 0 ) {
return "<a href=$arr[1]>$arr[1]</a>$arr[2]$arr[3]";
} else {
return "$arr[1]$arr[2]$arr[3]";
}
}
return preg_replace_callback( '/\b((?:http|www).+?)((?!\/)[\p{P}]+)?(\s|$)/x', replace, $string );
}
I added a callback so that all of the links would start with http://, and did some fiddling with the way it handles punctuation.
It's probably not the Best way to do things, but it works. I've learned a lot about this in the last little while, but there is still more to learn!
preg_replace('/
\b # Initial word boundary
( # Start capture
(?: # Non-capture group
http|www # http or www (alternation)
) # end group
.+? # reluctant match for at least one character until...
) # End capture
( # Start capture
[,.]+ # ...one or more of either a comma or period.
# add more punctuation as needed
)? # End optional capture
(\s|$) # Followed by either a space character or end of string
/x', '\1\2\3'
...is probably what you are going for. I think it's still imperfect, but it should at least work for your needs.
Aside: I think this is because \b matches punctuation too
You can achieve this with a positive lookahead assertion:
\b(http:|www\.)(?:[^\s,.!?]|[,.!?](?!\s))+
See it here on Regexr.
Means, match anything, but whitespace ,.!? OR match ,.!? when it is not followed by whitespace.
Aside: A word boundary is not a character or a set of characters, you can't put it into a character class. It is a zero width assertion, that is matching on a change from a word character to a non-word character. Here, I believe, \b in a character class is interpreted as the backspace character (the string escape sequence).
The problem may lie in the dot, which means "any character" in regex-speak. You'll probably have to escape it:
\b(http|www)\.?[^\s]+
Then, the question mark means 0 or 1 so you've said "an optional dot" which is not what you want (right?):
\b(http|www)\.[^\s]+
Now, it will only match http. and www. so you need to tell what other characters you'll let it accept:
\b(http|www)\.[^\s\w]+
or
\b(http|www)\.[^\sa-zA-Z]+
So now you're saying,
at the boundary of a word
check for http or www
put a dot
allow any range a-z or A-Z, don't allow any whitespace character
one or more of those
Note - I haven't tested these but they are hopefully correct-ish.
Aside (my take on it) - the \s means 'whitespace'. The \b means 'word boundary'. The [] means 'an allowed character range'. The ^ means 'not'. The + means 'one or more'.
So when you say [^\b]+ you're saying 'don't allow word boundaries in this range of characters, and there must be one or more' and since there's nothing else there > nothing else is allowed > there's not one or more > it probably breaks.
You should try something like this:
\b(http|www).?[\w\.\/]+

Categories