Tim
Tim

Reputation: 7056

Regex to disallow two characters in a row

I'm trying to modify this regex pattern so that it disallows two specified characters in a row or at the start/end -

/^[^\!\"\£\$\%\^\&\*\(\)\[\]\{\}\@\~\#\/\>\<\\\*]+$/

So at the moment it prevents these characters anywhere in the string, but I also want to stop the following from happening with these characters:

Any help would be hugely appreciated.

Thanks a lot

Upvotes: 0

Views: 2439

Answers (3)

piouPiouM
piouPiouM

Reputation: 5037

I'm not sure I understand the exact problem, but here's a suggestion:

<?php
$test     = "__-Remove '' _._ or -__- but not foo bar '. _  \n";
$expected = 'Remove or but not foo bar';

// The list of disallowed characters. There is no need to escape.
// This will be done with the function preg_quote.
$excluded_of_bounds = "'_.-";

// Remove disallowed characters from start/end of the string.
// We add the space characters that should not be in the regexp.
$test = trim($test, $excluded_of_bounds . " \r\n");

// In two passes
$patterns = array(
  // 1/ We remove all successive disallowed characters,
  //    excepted for the spaces
  '#[' . preg_quote($excluded_of_bounds) . ']{2,}#',
  // 2/ We replace the successive spaces by a unique space.
  '#\s{2,}#',
);
$remplacements = array('', ' ');

// Go!
$test = preg_replace($patterns, $remplacements, $test);

// bool(true)
var_dump($expected === $test);

Upvotes: 0

Cups
Cups

Reputation: 6896

$tests[1]     = "fail_.fail";  // doubles
$tests[]     = "fail_-fail";
$tests[]     = "fail_ fail";
$tests[]     = "fail  fail";
$tests[]     = "fail -fail";
$tests[]     = "pas.s_1";
$tests[]     = "pa.s-s_2"; // singles
$tests[]     = "pas.s_3";
$tests[]     = "p.a.s.s_4";
$tests[10]     = "pa s-s_5";
$tests[]     = "fail fail'"; // pre or post-pended
$tests[]     = " fail fail";
$tests[]     = " fail fail";
$tests[]     = "fail fail_";
$tests[15]     = "fail fail-";

// The list of disallowed characters. There is no need to escape.
// This will be done with the function preg_quote.
$exclude = array(" ","'", "_", ".", "-");

$pattern =  "#[" . preg_quote(join("", $exclude)) . "]{2,}#s";

// run through the simple test cases 

foreach($tests as $k=>$test){
if( 
    in_array(substr($test, 0, 1), $exclude)  
 || in_array(substr(strrev($test), 0 , 1) , $exclude))
   {
   echo "$k thats a fail" . PHP_EOL;
   continue;
   }

  $test = preg_match( $pattern,  $test);
    if($test === 1){
    echo "$k - thats a fail". PHP_EOL ;
    }else{
    echo "$k - thats a pass $test ". PHP_EOL ;
    }
}

Stealing hopelessly from other replies, I'd advocate using PHPs simple in_array to check the start and end of the string first and just fail early on discovering something bad.

If the test gets past that, then run a really simple regex.

Stick the lot into a function and return false on failure -- that would rm quite a few verbose lines I added -- you could even send in the exclusion array as a variable -- but it would seem rather a specific function so may be YAGNI

eg

if( badString($exclude_array, $input) ) // do stuff

Upvotes: 0

MikeM
MikeM

Reputation: 13631

One way

/^(?=[^!"£$%^&*()[\]{}@~#\/><\\*]+$)(?!.*[ '_.-]{2})[^ '_.-].*[^ '_.-]$/

Note, only tested as javascript regex, i.e.

var rex = /^(?=[^!"£$%^&*()[\]{}@~#\/><\\*]+$)(?!.*[ '_.-]{2})[^ '_.-].*[^ '_.-]$/;
rex.test('okay');        // true
rex.test('_not okay');   // false

Or, to match on disallowed patterns

/^[ '_.-]|[ '_.-]$|[!"£$%^&*()[\]{}@~#\/><\\*]|[ '_.-]{2}/

The first regex will only match strings that contain no disallowed patterns.
The one above will match any disallowed patterns in a string.

Update

Now tested briefly using php. The only difference is that the " in the character set needed to be escaped.

<?php
$test = 'some string';
$regex = "/^[ '_.-]|[ '_.-]$|[!\"£$%^&*()[\]{}@~#\/><\\*]|[ '_.-]{2}/";
if ( preg_match( $regex, $test ) ) {
    echo 'Disallowed!';
}

Upvotes: 1

Related Questions