diff --git a/ChangeLog b/ChangeLog
index fe783bc6640f1f2ee341566a1112b405f492d9f0..adf50d6db7c76f7a3fe102fe073a0e250b5e664f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -5,6 +5,9 @@ CVS Code -
 	  two strings that had no actual words in them that
 	  should be translated.	 Suggested originally by
 	  Christian Rose.
+	- Fix subexpression replacement to work consistently.
+	  Affects search.c:replace_regexp() and 
+	  utils.c:strstrwrapper() (David Benbennick).
 - cut.c:
   do_cut_text()
 	- Fix incorrect cursor location when cutting long lines
diff --git a/search.c b/search.c
index 71415649caffab06a3f6538dc25f99aad6545b85..c6c42a7ea636d2e1bfea67aca1036a4a36378068 100644
--- a/search.c
+++ b/search.c
@@ -445,10 +445,10 @@ int replace_regexp(char *string, int create_flag)
 	    c++;
 	    new_size++;
 	} else {
-	    int num = (int)(*(c + 1) - '0');
+	    int num = (int) *(c + 1) - (int) '0';
 	    if (num >= 1 && num <= 9) {
 
-		int i = regmatches[num].rm_so;
+		int i = regmatches[num].rm_eo - regmatches[num].rm_so;
 
 		if (num > search_regexp.re_nsub) {
 		    /* Ugh, they specified a subexpression that doesn't
@@ -460,12 +460,15 @@ int replace_regexp(char *string, int create_flag)
 		c += 2;
 
 		/* But add the length of the subexpression to new_size */
-		new_size += regmatches[num].rm_eo - regmatches[num].rm_so;
+		new_size += i;
 
 		/* And if create_flag is set, append the result of the
 		 * subexpression match to the new line */
-		while (create_flag && i < regmatches[num].rm_eo)
-		    *string++ = *(current->data + i++);
+		if (create_flag) {
+		    strncpy(string, current->data + current_x +
+			    regmatches[num].rm_so, i);
+		    string += i;
+		}
 
 	    } else {
 		if (create_flag)
diff --git a/utils.c b/utils.c
index 557624b7e43aea8d39231d6aa36229b2181caaf2..6d3f8f1190cc578bd3f63dc9c0a4fc63d9728851 100644
--- a/utils.c
+++ b/utils.c
@@ -138,50 +138,58 @@ const char *stristr(const char *haystack, const char *needle)
     return NULL;
 }
 
+/* If we are searching backwards, we will find the last match
+ * that starts no later than rev_start.  If we are doing a regexp search,
+ * then line_pos should be 0 if haystack starts at the beginning of a
+ * line, and positive otherwise.  In the regexp case, we fill in the
+ * global variable regmatches with at most 9 subexpression matches.  Also,
+ * all .rm_so elements are relative to the start of the whole match, so
+ * regmatches[0].rm_so == 0. */
 const char *strstrwrapper(const char *haystack, const char *needle,
 			const char *rev_start, int line_pos)
 {
 #ifdef HAVE_REGEX_H
     if (ISSET(USE_REGEXP)) {
-	if (!ISSET(REVERSE_SEARCH)) {
-	    if (!regexec(&search_regexp, haystack, 10, regmatches, (line_pos > 0) ? REG_NOTBOL : 0))
-		return haystack + regmatches[0].rm_so;
-	}
 #ifndef NANO_SMALL
-	else {
-	    const char *i, *j;
-
-	    /* do a quick search forward first */
-	    if (!regexec(&search_regexp, haystack, 10, regmatches, 0)) {
-		/* there's a match somewhere in the line - now search for it backwards, much slower */
-		for (i = rev_start; i >= haystack; --i) {
-		    if (!regexec(&search_regexp, i, 10, regmatches, (i > haystack) ? REG_NOTBOL : 0)) {
-			j = i + regmatches[0].rm_so;
-			if (j <= rev_start)
-			    return j;
-		    }
-		}
+	if (ISSET(REVERSE_SEARCH)) {
+		/* When doing a backwards search, haystack is a whole line. */
+	    if (!regexec(&search_regexp, haystack, 1, regmatches, 0) &&
+		    haystack + regmatches[0].rm_so <= rev_start) {
+		const char *retval = haystack + regmatches[0].rm_so;
+
+		/* Search forward until there is no more match. */
+		while (!regexec(&search_regexp, retval + 1, 1, regmatches,
+			    REG_NOTBOL) &&
+			retval + 1 + regmatches[0].rm_so <= rev_start)
+		    retval += 1 + regmatches[0].rm_so;
+		/* Finally, put the subexpression matches in global
+		 * variable regmatches.  The REG_NOTBOL flag doesn't
+		 * matter now. */
+		regexec(&search_regexp, retval, 10, regmatches, 0);
+		return retval;
 	    }
+	} else
+#endif /* !NANO_SMALL */
+	if (!regexec(&search_regexp, haystack, 10, regmatches,
+			line_pos > 0 ? REG_NOTBOL : 0)) {
+	    const char *retval = haystack + regmatches[0].rm_so;
+
+	    regexec(&search_regexp, retval, 10, regmatches, 0);
+	    return retval;
 	}
-#endif
-	return 0;
+	return NULL;
     }
-#endif
+#endif /* HAVE_REGEX_H */
 #ifndef NANO_SMALL
     if (ISSET(CASE_SENSITIVE)) {
 	if (ISSET(REVERSE_SEARCH))
 	    return revstrstr(haystack, needle, rev_start);
-        else
-	    return strstr(haystack, needle);
-    } else {
-	if (ISSET(REVERSE_SEARCH))
-	    return revstristr(haystack, needle, rev_start);
 	else
+	    return strstr(haystack, needle);
+    } else if (ISSET(REVERSE_SEARCH))
+	return revstristr(haystack, needle, rev_start);
 #endif
-	    return stristr(haystack, needle);
-#ifndef NANO_SMALL
-    }
-#endif
+    return stristr(haystack, needle);
 }
 
 /* This is a wrapper for the perror function.  The wrapper takes care of