php – Alternative strings in regular expression-ThrowExceptions

Exception or error:

Sadly I have to ask this question but after noodling on this problem the whole morning, I give up. Searching online, man pages, documents, none of it seems to give me a conclusive answer to what I try to do.

Looking for a regular expression for the PHP function preg_match to match a string against a pattern. Now that pattern is what gives me headaches.

The pattern should express the following: string starts with “_MG_” or “IMG_” or “DSC_”, followed by four digits, followed by an optional “-N” where N is another digit. For example, “IMG_0123” or “DSC_9876-3” are valid. Everything else should be rejected.

I came up with various patterns, but none of them seems to work. For example, I tried

(_MG_|IMG_|DSC_)[0-9]{4}(-[0-9])?

and this in different variations with ( ) and apostrophes around various sub-expressions and using ? vs {0,1} and whatnot. (I experimented using grep, but got no matches still.) Yes, I know I need to add “/…/” for PHP, but here I left it out for readability’s sake.

Can I even express this in a single expressions, or will I have to call the matching function several times? If several matches are required, I might be better off writing a small parser for this particular string matching myself.

Thanks!

EDIT: Here is the code that I’m working with

// Iterate over all images in this gallery folder.
if ($h = opendir($dir)) {
  while (($f = readdir($h)) !== false) {

    // Skip images whose name doesn't match the requirement.
    if (0 == preg_match("/(_MG_|IMG_|DSC_)[0-9]{4}(-[0-9]){0,1}/", $f)) {
      continue;
    }

    ...
  }
}

And this also allows image names like “_MG_7020-1-2.jpg” or “_MG_7444-5-6.2.jpg” or “IMG_6543_2_4_tonemapped.jpg” but that’s not what I want to allow.

How to solve:
<?php

    $array = array('IMG_0123', 'DSC_9876-3', '_MG_1234', 'DSC_fail');

    foreach($array as $arr) {
        if(preg_match("/_MG_|IMG_|DSC_[0-9]{4}[-0-9]*/", $arr)) {
            echo $arr . ' => TRUE <br />';
        } else {
            echo $arr . ' => FALSE <br />';
        }
    }
?>

The above works as expected for me.

Answer:

I ran this as well:

<?php
$matches = array();
preg_match('/(_MG_|IMG_|DSC_)[0-9]{4}(-[0-9])?/','IMG_0123-3',$matches );

var_dump($matches);

Output:

array(3) {
  [0]=>
  string(10) "IMG_0123-3"
  [1]=>
  string(4) "IMG_"
  [2]=>
  string(2) "-3"
}

Seems ok, unless I’m missing something, or unless what you’re referring to is that preg_match returns false if not all your matchers () match.

Note the return type for preg_match from the php doc:

preg_match() returns the number of times pattern matches. That will be either 0 times (no match) or 1 time because preg_match() will stop searching after the first match. preg_match_all() on the contrary will continue until it reaches the end of subject. preg_match() returns FALSE if an error occurred.

So you may be looking to really use preg_match_all() in fact

Answer:

According to this refiddle, you seem to have it solved just fine. You can use their “unit” test functionality additional “should” and “should not” match scenarios. Granted, that refiddle is using javascript’s regex, but I find them to be effectively identical until you get into backreferences and lookarounds.

Leave a Reply

Your email address will not be published. Required fields are marked *