Index: wp-includes/functions.php
===================================================================
--- wp-includes/functions.php	(revision 10308)
+++ wp-includes/functions.php	(working copy)
@@ -2366,6 +2366,7 @@
 	return $input;
 }
 
+
 /**
  * Convert smiley code to the icon graphic file equivalent.
  *
@@ -2376,13 +2377,8 @@
  * to an array, with the key the code the blogger types in and the value the
  * image file.
  *
- * The $wp_smiliessearch global is for the regular expression array and is
- * set each time the function is called. The $wp_smiliesreplace is the full
- * replacement. Supposely, the $wp_smiliessearch array is looped over using
- * preg_replace() or just setting the array of $wp_smiliessearch along with the
- * array of $wp_smiliesreplace in the search and replace parameters of
- * preg_replace(), which would be faster and less overhead. Either way, both are
- * used with preg_replace() and can be defined after the function is called.
+ * The $wp_smiliessearch global is for the regular expression and is set each
+ * time the function is called.
  *
  * The full list of smilies can be found in the function and won't be listed in
  * the description. Probably should create a Codex page for it, so that it is
@@ -2449,12 +2445,38 @@
 		);
 	}
 
-	$siteurl = get_option( 'siteurl' );
+	if (count($wpsmiliestrans) == 0) {
+		return;
+	}
+
+	/*
+	 * NOTE: we sort the smilies in reverse key order. This is to make sure
+	 * we match the longest possible smilie (:???: vs :?) as the regular
+	 * expression used below is first-match
+	 */
+	krsort($wpsmiliestrans);
+
+	$wp_smiliessearch = '/(?:\s|^)';
+
+	$subchar = '';
 	foreach ( (array) $wpsmiliestrans as $smiley => $img ) {
-		$wp_smiliessearch[] = '/(\s|^)' . preg_quote( $smiley, '/' ) . '(\s|$)/';
-		$smiley_masked = attribute_escape( trim( $smiley ) );
-		$wp_smiliesreplace[] = " <img src='$siteurl/wp-includes/images/smilies/$img' alt='$smiley_masked' class='wp-smiley' /> ";
+		$firstchar = substr($smiley, 0, 1);
+		$rest = substr($smiley, 1);
+
+		// new subpattern?
+		if ($firstchar != $subchar) {
+			if ($subchar != '') {
+				$wp_smiliessearch .= ')|';
+			}
+			$subchar = $firstchar;
+			$wp_smiliessearch .= preg_quote($firstchar, '/') . '(?:';
+		} else {
+			$wp_smiliessearch .= '|';
+		}
+		$wp_smiliessearch .= preg_quote($rest);
 	}
+
+	$wp_smiliessearch .= ')(?:\s|$)/';
 }
 
 /**
Index: wp-includes/formatting.php
===================================================================
--- wp-includes/formatting.php	(revision 10308)
+++ wp-includes/formatting.php	(working copy)
@@ -1218,14 +1218,44 @@
 	return "<a $text rel=\"nofollow\">";
 }
 
+
 /**
+ * Convert one smiley code to the icon graphic file equivalent.
+ *
+ * Looks up one smiley code in the $wpsmiliestrans global array and returns an
+ * <img> string for that smiley.
+ *
+ * @global array $wpsmiliestrans
+ * @since 2.8.0
+ *
+ * @param string $smiley Smiley code to convert to image.
+ * @return string Image string for smiley.
+ */
+function translate_smiley($smiley) {
+	global $wpsmiliestrans;
+
+	if (count($smiley) == 0) {
+		return '';
+	}
+
+	$siteurl = get_option( 'siteurl' );
+
+	$smiley = trim(reset($smiley));
+	$img = $wpsmiliestrans[$smiley];
+	$smiley_masked = attribute_escape($smiley);
+
+	return " <img src='$siteurl/wp-includes/images/smilies/$img' alt='$smiley_masked' class='wp-smiley' /> ";
+}
+
+
+/**
  * Convert text equivalent of smilies to images.
  *
- * Will only convert smilies if the option 'use_smilies' is true and the globals
- * used in the function aren't empty.
+ * Will only convert smilies if the option 'use_smilies' is true and the global
+ * used in the function isn't empty.
  *
  * @since 0.71
- * @uses $wp_smiliessearch, $wp_smiliesreplace Smiley replacement arrays.
+ * @uses $wp_smiliessearch
  *
  * @param string $text Content to convert smilies from text.
  * @return string Converted content with text smilies replaced with images.
@@ -1233,14 +1263,14 @@
 function convert_smilies($text) {
 	global $wp_smiliessearch, $wp_smiliesreplace;
 	$output = '';
-	if ( get_option('use_smilies') && !empty($wp_smiliessearch) && !empty($wp_smiliesreplace) ) {
+	if ( get_option('use_smilies') && !empty($wp_smiliessearch) ) {
 		// HTML loop taken from texturize function, could possible be consolidated
 		$textarr = preg_split("/(<.*>)/U", $text, -1, PREG_SPLIT_DELIM_CAPTURE); // capture the tags as well as in between
 		$stop = count($textarr);// loop stuff
 		for ($i = 0; $i < $stop; $i++) {
 			$content = $textarr[$i];
 			if ((strlen($content) > 0) && ('<' != $content{0})) { // If it's not a tag
-				$content = preg_replace($wp_smiliessearch, $wp_smiliesreplace, $content);
+				$content = preg_replace_callback($wp_smiliessearch, 'translate_smiley', $content);
 			}
 			$output .= $content;
 		}
