7

Im trying to create a regular expression in PHP which is checking that a string conforms to the following rules:

  • Has 1 - 7 occurrences of one of the following strings (Mon,Tues,Wed,Thurs,Fri,Sat,Sun)
  • Strings separated by a ,
  • not case sensitive
  • No strings are repeated.

I believe I have fulfilled the first three aspects of this with the following:

/^(Mon|Tues|Wed|Thurs|Fri|Sat|Sun)(,(Mon|Tues|Wed|Thurs|Fri|Sat|Sun)){0,6}$/i

I am struggling to get to grips with preventing any repeats. Can anyone advise?

  • 1
    [This question](http://stackoverflow.com/questions/7780794/javascript-regex-remove-duplicate-characters) and [this one](http://stackoverflow.com/questions/2823016/regular-expression-for-consecutive-duplicate-words) might help with the duplicates. You might need two passes -- it's easier to use a regex to match duplicates than to match no duplicates. – Blazemonger Sep 17 '13 at 14:14

2 Answers2

5

Does it have to be a regex? If not:

$daysStart = 'Mon,Tues,Wed,mon';
$days = strtolower($daysStart);
$days = explode(",", $days); // split on comma
$days = array_unique($days); // remove uniques
$days = implode(",", $days); // join on comma

// Compare new string to original:
if(strtolower($days)===strtolower($daysStart )){ /*match*/ }

This results in a lowercase string of days, seperated by commas. Not sure what you wanted as output, you might want to save the original input in another far, or ucfirst() the values via an array_map() or something, this is just to show you another method


Or my code shorter:

$daysStart = 'Mon,Tues,Wed,mon';
$days = explode(",", strtolower($daysStart ) );
$days = implode(",", array_unique($days) );
if(strtolower($days)===strtolower($daysStart )){ /*match*/ }

or function (as short code, can be the longer version ofcourse):

function checkDays($string){
    $days = explode(",", strtolower($string) );
    $days = implode(",", array_unique($days) );
    return (strtolower($days)===strtolower($daysStart)) ? true : false;// *
}

*I could've done just the return and the str-checks, but I prefer to add true/false in a way im sure my returnvalue always is true of false as boolean, not truthy or falsy.

Martijn
  • 15,791
  • 4
  • 36
  • 68
5
^(Mon|Tues|Wed|Thurs|Fri|Sat|Sun)(?:,(?!\1|\2)(Mon|Tues|Wed|Thurs|Fri|Sat|Sun)){0,6}$

You could use this if regex is an absolute requirement but I'd rather recommend Martijn's answer. It is much more flexible and easier to read.

Here is how i tested this in PHP:

<?php

$subject1 = "Mon,Mon";
$subject2 = "Sun,Mon,Fri,Sun";
$subject3 = "Sat";
$subject4 = "Mon,Wed,Tues,Fri,Wed";
$subject5 = "Mon,Tues";
$pattern = '/^(Mon|Tues|Wed|Thurs|Fri|Sat|Sun)(?:,(?!\1|\2)(Mon|Tues|Wed|Thurs|Fri|Sat|Sun)){0,6}$/i';
print_r(preg_match($pattern, $subject1, $matches) . " " . $subject1 . "\n");
print_r(preg_match($pattern, $subject2, $matches) . " " . $subject2 . "\n");
print_r(preg_match($pattern, $subject3, $matches) . " " . $subject3 . "\n");
print_r(preg_match($pattern, $subject4, $matches) . " " . $subject4 . "\n");
print_r(preg_match($pattern, $subject5, $matches) . " " . $subject5 . "\n");

?>

This outputs:

0 Mon,Mon
0 Sun,Mon,Fri,Sun
1 Sat
1 Mon,Wed,Tues,Fri,Wed
1 Mon,Tues
Martijn
  • 15,791
  • 4
  • 36
  • 68
JonM
  • 1,314
  • 10
  • 14
  • Thanks for the input. I have tested this using preg_match and it still matches "Mon,Mon" – Abdul Razak Sep 17 '13 at 14:27
  • [preg_match test](http://www.switchplane.com/awesome/preg-match-regular-expression-tester/?pattern=%2F^%28Mon|Tues|Wed|Thurs|Fri|Sat|Sun%29%28%3F%3A%2C%28%3F!\1|\2%29%28Mon|Tues|Wed|Thurs|Fri|Sat|Sun%29%29{0%2C6}%24%2F&subject=Mon%2CMon) It seems to work as proposed when using this testing tool... – JonM Sep 17 '13 at 14:32
  • Sorry still slightly confused. I can see it works on preg_match test you've linked to. I copy the exact regex into php, use preg_match there and it comes up as a match – Abdul Razak Sep 17 '13 at 14:47
  • preg_match() will return zero instead of false. This is the indication that the string hasn't met your requirements. – JonM Sep 17 '13 at 14:50
  • Hi Jon, yes and in the test I run it is returning 1. $string = "Mon,Mon" $regex copied straight from your answer. Confusing :S – Abdul Razak Sep 17 '13 at 14:55
  • Hmm seems to be returning 0 for me... What version of PHP are you using? – JonM Sep 17 '13 at 15:06
  • Hi, its PHP Version 5.4.12 – Abdul Razak Sep 17 '13 at 15:10
  • Hi JonM. Thank you for all your assistance. I had the pattern in double quotes rather than single. Not sure why this worked with some subjects and not others, but changing to single quotes allowed all subjects to pass. Thank You. – Abdul Razak Sep 17 '13 at 15:20
  • 1
    No worries! I am very guilty of using inconsistent quotes (as you can probably see from my answer). It drives some of my co workers crazy but I am trying to get better. This answer explains the effect of different quotes in PHP http://stackoverflow.com/questions/3446216/what-is-the-difference-between-single-quoted-and-double-quoted-strings-in-php – JonM Sep 17 '13 at 15:22