Normalizing strings using PHP preg_replace and regex expressions I needed a way to normalize nearly any given input for a configuration parameter on a dashboard.  Server side code is in PHP so I wrote a test script to experiment with preg_replace and regex.  When I say normalize meaning, the resulting value must match the following restrictions:


Take any cased value and return all lower case. For example, given "ValiDVoicE", after normalizing, "validvoice" would be returned.
Strip away all special characters and white space except underscores. For example, given "@@Valid  _voice" return only "valid_voice".
Trim all nonessential white space from front and end of string. For example, given "&nbsp;&nbsp;&nbsp;(&amp;&amp;   (*Paxus-Demo&nbsp;&nbsp;&nbsp;&nbsp;" return "paxus_demo".


Solution: (I copied my test script below)

$myvar = 
[ 
    "Paxus-Demo", 
    "Paxus Demo", 
    "paxus_demo", 
    "Paxus  Demo", 
    "paxus-Demo", 
    "paxus_ Demo", 
    "Paxus _Demo", 
    "*(&amp;*&amp;   (*Paxus-Demo   ", 
    "@@Valid  _voice",
    "Valid-Voice",
    "PortaL-Demo",
    "gui_demo",
    "Gui-Demo   ",
    "VoiceInstance",
    "vAlid Voice",
    "  vaLid_  _voiCe  ",
];

for( $i = 0; $i &lt; sizeof( $myvar ); ++$i )
{
    $modded = trim( strtolower( preg_replace( array( '/[^a-zA-Z0-9 ]/i', '&lt;\W+&gt;'), array( ' ', '_' ), $myvar[$i] ) ), '_' );
    echo "modded2 = " . $modded." [ ". $i ." ] = " .$myvar[$i]. "&lt;br /&gt;";
}


My question is not necessarily for elegance, but could I have done this all in one regex expression using lookarounds?  Bear in mind, I never took the time to truly understand using regex before today so my knowledge of using lookarounds is still a bit wonky.  That said, if someone can simplify the use of lookarounds it'll be greatly appreciated.
At first glance I would first trim without a mask and then stringtolower inside before the preg_replace.

$modded = preg_replace(array( '/[^a-z0-9 ]/','&lt;\W+&gt;'),array( ' ', '_' ), strtolower(trim( $myvar[$i])));



trim first, less characters to process when there is white space to
trim.
Then stringtolower() which allows '/[^a-zA-Z0-9 ]/i' to be
simplified to '/[^a-z0-9 ]/'


Case insensitive tasks require extra CPU cycles.
RegEx is the usually least efficient string function especially compared to stringtolower() and trim()
Using these two function before the RegEx gives the RegEx less work to do.
Consider giving the trim additional mask characters: e.g.
space, new line, carriage return, asterisk, ampersand, at mark, parenthesisPlus any other characters that could need to be trimmed (quote marks?).

This worked well for you test $myvar:

trim($str," \t\n\r\0\x0B\x28\x29\x26\x2a\x40\x5f")


RegEx is not my strong suit.  While it works well this does not make sense to me. '/[^a-z0-9 ]/','&lt;\W+&gt;' I'm not saying it is wrong, it's not broke,  I just do not fully understand.

some minor stuff that bugs me:
You do not need to concatenate simple variables in double quotes

echo "modded2 = " . $modded." [ ". $i ." ] = " .$myvar[$i]. "\n";


This is the same but cleaner:

echo "modded2 = $modded [$i] = $myvar[$i]\n";


This may be more efficient, (or may not, did not benchmark):

for( $i = 0; $i &lt; sizeof( $myvar ); ++$i )


But this is cleaner, easier to see what is going on.

foreach($myvar as $key =&gt; $value){


My preference is count over sizeof, although they are the same.

In a test environment like this, instead of &lt;br&gt; I use "\n" with a plain text header:

header('Content-Type: text/plain; charset=utf-8');


It works will with print_r() and var_export(), var_dump() etc.

My Tested Code:

header('Content-Type: text/plain; charset=utf-8');
$myvar = array("Paxus-Demo","Paxus Demo","paxus_demo","Paxus  Demo",
    "paxus-Demo","paxus_ Demo","Paxus _Demo","*(&amp;*&amp;   (*Paxus-Demo   ",
    "@@Valid  _voice","Valid-Voice","PortaL-Demo","gui_demo",
    "Gui-Demo   ",    "VoiceInstance","vAlid Voice","  vaLid_  _voiCe  ");



foreach($myvar as $k =&gt; $before){
  $after = preg_replace( array( '/[^a-z0-9 ]/','&lt;\W+&gt;'), array( ' ', '_' ), strtolower(trim($before," \t\n\r\0\x0B\x28\x29\x26\x2a\x40\x5f" )));
//  echo "$k. $before =&gt; $after\n";
  echo "$k. $after &lt;= \"$before\"\n";
}


The Result:

0. paxus_demo &lt;= "Paxus-Demo"
1. paxus_demo &lt;= "Paxus Demo"
2. paxus_demo &lt;= "paxus_demo"
3. paxus_demo &lt;= "Paxus  Demo"
4. paxus_demo &lt;= "paxus-Demo"
5. paxus_demo &lt;= "paxus_ Demo"
6. paxus_demo &lt;= "Paxus _Demo"
7. paxus_demo &lt;= "*(&amp;*&amp;   (*Paxus-Demo   "
8. valid_voice &lt;= "@@Valid  _voice"
9. valid_voice &lt;= "Valid-Voice"
10. portal_demo &lt;= "PortaL-Demo"
11. gui_demo &lt;= "gui_demo"
12. gui_demo &lt;= "Gui-Demo   "
13. voiceinstance &lt;= "VoiceInstance"
14. valid_voice &lt;= "vAlid Voice"
15. valid_voice &lt;= "  vaLid_  _voiCe  "