Tom Wright Tom Wright - 4 months ago 7
PHP Question

PHP Regex - Matching one of a character group, when ONE of that character group is not in a string

I feel like I've been hitting my head against a brick wall.

I have a string that looks like this:

$record['filenameGood'] = '49161_Comma_Dataphoria-Clickwork7Export{DATE:dmY}';

And I want to block filenames that contain any restricted characters.

However... I am using a placeholder for the current date, which looks like
would get inserted into
This part I am fine with, it's just ensuring that the rest of the string doesn't contain a restricted character.

The script I am testing with looks like this:

// Matches one of " * : % $ / \ ' ?
$patternOne = '#["*:%$/\\\'?]#';

// Desired: matches one of " * : % $ / \ ' ?, but ALLOWS {DATE:.*?}
$patternTwo = '#["*:%$/\\\'?]#';
$record = [];
$record['filenameGood'] = '49161_Comma_Dataphoria-Clickwork7Export{DATE:dmY}';
$record['filenameBad'] = '49161_Comma_Dataphoria-Clickwork7:Export{DATE:dmY}';

var_dump(preg_match($patternTwo, $record['filenameGood']));
var_dump(preg_match($patternTwo, $record['filenameBad']));

The current output is:


Whereas my desired output is:

int(0) // Good string, contains : within {DATE:}
int(1) // Bad string, contains a : NOT within {DATE:}

I also need a string like the following to get matched:


I hope I've explained this well enough for you to understand!


You can use a negative lookbehind after the character class:

$patternTwo = '#["*:%$/\\\\\'?](?<!\b{DATE:)#';

See the IDEONE demo.

Here, one of the characters in the character class is matched first, but then the negative lookbehind will check if the : is not preceded with {DATE. If it is, the match will be failed.