Regex replace all matches if the match is not at the end of the string
I am currently using this regex to replace all non-abelian numeric characters from a string and replace them with a dash
$newString = preg_replace("/[^a-z0-9.]+/i", "-", $string);
This one works great for the next line.
$string = "this will work fine";
$newString = "this-will-work-fine";
But , if the string has a non-alpha numeric, as the final character, it will match and replace it, as one would suspect.
$string = "How can I fix this?";
$newString = "How-can-I-fix-this-";
How can I improve this regex to have the following output?
$newString = "How-can-I-fix-this";
Regular expression should work in cases . I know I can just trim the string using a separate function, but ideally I would like to use a single regex. Is it possible?
source to share
Since you are using PHP, you can define multiple patterns and replacements in one go. Here's a quick demo:
$string = "How can I fix this?";
$patterns = array('/[^0-9a-z.]+/i', '/[^0-9a-z.]+(?=$)/i');
$replacements = array('-', '');
echo preg_replace($patterns, $replacements, $string) . "\n";
which prints:
How-can-I-fix-this
In fact, these are no more than two consecutive replacements:
$string = "How can I fix this?";
echo preg_replace('/[^0-9a-z.]+/', '-', preg_replace('/[^0-9a-z.]+$/', '', $string)) . "\n";
source to share
Actually, this can be done in a single regex:
$newString = preg_replace('/[^a-z0-9.]++([a-z0-9.]++)(?:[^a-z0-9.]++$)?/i', '-$1', $string);
Note:
- For future reference
'-\1'
,'-\\1'
,"-\\1"
and"-$1"
all valid alternatives to replace the line. - Possessive quantifiers are not needed in this case. However, I always use them, even when the speed improvement is minor.
EDIT:
The third case (where the first character is not literal) can also be done with a single regex:
$newString = preg_replace('/(?:^[^a-z0-9.]++([a-z0-9.]++))?[^a-z0-9.]++([a-z0-9.]++)(?:[^a-z0-9.]++$)?/i', '$1-$2', $string);
source to share