preg_match: not this character, including no character

How should this be done? I’ve got:

echo preg_match(‘/asdf1[^0-9]/’,‘asdf1’);

and I want that to be a match, but it isn’t.

So I want to match asdf1 so long as it’s not followed by a digit. In the above example it isn’t followed by a digit (nor any other character) but doesn’t match. I suppose [^0-9] says “a character which isn’t 0…9”, and there isn’t a character following on. That’s why it’s not matching. So how do I say “not these characters, including no character”?

Thanks.

You need to add ? after your [^0-9] range to mark it optional. But that may have unwanted results, so can you provide some examples of what should match and what should not match?

Example of what you may want (you’d want to remove the mg when you implement it, as I simply added that so I could have all of my tests in a single file)

Oh yeah, I knew that really, god I’m not thinking straight today. Thanks.

Actually, no, that doesn’t work. Eg:

echo preg_match(‘/asdf1[^0-9]?/’,‘asdf11’);

gives a match.

Check out the regex101 link in my prior post. That I believe is more of what you want.

It uses
/asdf(1$|1[^0-9]$)/

Yup, that does it. Thanks.

Just chiming in with what may be a more appropriate/extensible solution:

The process you’re looking for is called a “look ahead” (http://www.regular-expressions.info/lookaround.html). The look ahead will look at the next character(s) that have been matched to the point in your regex where the look ahead is found, but won’t return what is found as part of your match.

You want to match the following examples:

asdf1
asdf1a
asdf1_

but not the following:

asdf11
asdf12

/asdf1(?![0-9])/

This is a negative look ahead, which will match asdf1, then look at the next character and will record a match as long as the next character (if any) is not a number.

As I said, the regular expression won’t return the content the look ahead matches (e.g. if you’re looking to replace the character after the 1, that character won’t be included in the replacement).

A less verbose way of doing the same would be:

/asdf1[^0-9]?$/

Your regex (at least, the part in parentheses) says, match either a 1 at the end of the string or a 1 followed by a non-digit character at the end of the string. Mine says, match a 1 optionally followed by a non-digit character at the end of the string.

Bonus points

It’s not 100% clear from the thread but you probably also want to “anchor” the beginning of the match, just like you’re doing for the end (with $). Currently, the regex will successfully match a string like “testasdf1”. If you wish to make certain that the string starts with “asdf” then you can use the special caret character (^), which in simple terms says “this must be the start of the string”. So:

/^asdf1[^0-9]?$/

Finally, the $ character has an annoying(ly useful) little quirk: it accepts a trailing newline character. That means the string asdf1\n (where \n is a newline character) would successfully match against the regex, even though there is the extra newline character in the string. Thankfully, there is a special option (you’ll also see the term “pattern modifier” used) that we can use to modify the meaning of $ to work in the more sensible “match at the end, and only at the end” manner.

/^asdf1[^0-9]?$/D

References

  1. http://php.net/manual/en/reference.pcre.pattern.modifiers.php
    Documentation of the regex modifiers, including “D” used above
1 Like

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.