Question

I want to create a url friendly string (one that will only contain letters, numbers and hyphens) from a user input to :

  1. remove all characters which are not a-z, 0-9, space or hyphens
  2. replace all spaces with hyphens
  3. replace multiple hyphens with a single hyphen

Expected outputs :

my project -> my-project 
test    project -> test-project
this is @ long str!ng with spaces and symbo!s -> this-is-long-strng-with-spaces-and-symbos

Currently i'm doing this in 3 steps :

$identifier = preg_replace('/[^a-zA-Z0-9\-\s]+/','',strtolower($project_name)); // remove all characters which are not a-z, 0-9, space or hyphens

$identifier = preg_replace('/(\s)+/','-',strtolower($identifier)); // replace all spaces with hyphens

$identifier = preg_replace('/(\-)+/','-',strtolower($identifier)); // replace all hyphens with single hyphen

Is there a way to do this with one single regex ?

Was it helpful?

Solution

Yeah, @Jerry is correct in saying that you can't do this in one replacement as you are trying to replace a particular string with two different items (a space or dash, depending on context). I think Jerry's answer is the best way to go about this, but something else you can do is use preg_replace_callback. This allows you to evaluate an expression and act on it according to what the match was.

$string = 'my project
test    project
this is @ long str!ng with spaces and symbo!s';

$string = preg_replace_callback('/([^A-Z0-9]+|\s+|-+)/i', function($m){$a = '';if(preg_match('/(\s+|-+)/i', $m[1])){$a = '-';}return $a;}, $string);

print $string;

Here is what this means:

  • /([^A-Z0-9]+|\s+|-+)/i This looks for any one of your three quantifiers (anything that is not a number or letter, more than one space, more than one hyphen) and if it matches any of them, it passes it along to the function for evaluation.
  • function($m){ ... } This is the function that will evaluate the matches. $m will hold the matches that it found.
  • $a = ''; Set a default of an empty string for the replacement
  • if(preg_match('/(\s+|-+)/i', $m[1])){$a = '-';} If our match (the value stored in $m[1]) contains multiple spaces or hyphens, then set $a to a dash instead of an empty string.
  • return $a; Since this is a function, we will return the value and that value will be plopped into the string wherever it found a match.

Here is a working demo

OTHER TIPS

I don't think there's one way of doing that, but you could reduce the number of replaces and in an extreme case, use a one liner like that:

$text=preg_replace("/[\s-]+/",'-',preg_replace("/[^a-zA-Z0-9\s-]+/",'',$text));

It first removes all non-alphanumeric/space/dash with nothing, then replaces all spaces and multiple dashes with a single one.

Since you want to replace each thing with something different, you will have to do this in multiple iterations.

Sorry D:

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top