For maintainability and readability, I would change your emoticons array to:
$emoticons = array(
'happy' => array( ':)', ':]'),
'sad' => array( ':(', ':[')
);
Then, you can form a look-up table just like you originally had, like this:
$emoticon_lookup = array();
foreach( $emoticons as $name => $values) {
foreach( $values as $emoticon) {
$emoticon_lookup[ $emoticon ] = $name;
}
}
Now, you can dynamically form a regex from the emoticon lookup array. Note that this regex requires a non-word-boundary surrounding the emoticon, change it to what you need.
$escaped_emoticons = array_map( 'preg_quote', array_keys( $emoticon_lookup), array_fill( 0, count( $emoticon_lookup), '/'));
$regex = '/\B(' . implode( '|', $escaped_emoticons) . ')\B/';
And then use preg_replace_callback()
with a custom callback to implement the replacement:
$str = preg_replace_callback( $regex, function( $match) use( $emoticon_lookup) {
return $emoticon_lookup[ $match[1] ];
}, $str);
You can see from this demo that this outputs:
Am I happy or sad today?