diff --git a/ChangeLog b/ChangeLog
index 6803a3dfd98cdfcd6b9ba72f11b1b933bb1eeb35..fe783bc6640f1f2ee341566a1112b405f492d9f0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -24,6 +24,10 @@ CVS Code -
 	- Revamp -H option message to fit in 80 column terminal.
   window_init()
 	- Fix leaking *WINDOWs (no pun intended) (David Benbennick).
+- search.c:
+  do_replace_loop()
+	- Fix various bugs having to do with replace string length
+	  and positioning (David Benbennick).
 - winio.c:
   bottombars()
 	- Change strcpy of gettext() "Up" string to strncpy of max
diff --git a/search.c b/search.c
index cd1ed7935ebf3d2f3a86fc225cc208136899b9fc..71415649caffab06a3f6538dc25f99aad6545b85 100644
--- a/search.c
+++ b/search.c
@@ -597,6 +597,9 @@ int do_replace_loop(const char *prevanswer, const filestruct *begin,
 	}
 
 	if (*i > 0 || replaceall) {	/* Yes, replace it!!!! */
+	    long length_change;
+	    size_t match_len;
+
 	    if (*i == 2)
 		replaceall = 1;
 
@@ -607,38 +610,43 @@ int do_replace_loop(const char *prevanswer, const filestruct *begin,
 		return 0;
 	    }
 
-	    /* Cleanup */
-	    totsize -= strlen(current->data);
-	    free(current->data);
-	    current->data = copy;
-	    totsize += strlen(current->data);
-
-	    if (!ISSET(REVERSE_SEARCH)) {
-		/* Stop bug where we replace a substring of the
-		   replacement text */
-		current_x += strlen(last_replace) - 1;
+	    length_change = strlen(copy) - strlen(current->data);
 
-		/* Adjust the original cursor position - COULD BE IMPROVED */
-		if (search_last_line) {
-		    *beginx += strlen(last_replace) - strlen(last_search);
+#ifdef HAVE_REGEX_H
+	    if (ISSET(USE_REGEXP))
+		match_len = regmatches[0].rm_eo - regmatches[0].rm_so;
+	    else
+#endif
+		match_len = strlen(prevanswer);
 
-		    /* For strings that cross the search start/end boundary */
+#ifndef NANO_SMALL
+	    if (current == mark_beginbuf && mark_beginx > current_x) {
+		if (mark_beginx < current_x + match_len)
+		    mark_beginx = current_x;
+		else
+		    mark_beginx += length_change;
+	    }
+#endif
 
-		    /* Don't go outside of allocated memory */
-		    if (*beginx < 1)
-			*beginx = 1;
-		}
-	    } else {
-		if (current_x > 1)
-		    current_x--;
+	    assert(0 <= match_len + length_change);
+	    if (current == begin && current_x <= *beginx) {
+		if (*beginx < current_x + match_len)
+		    *beginx = current_x + match_len;
+		*beginx += length_change;
+	    }
 
-		if (search_last_line) {
-		    *beginx += strlen(last_replace) - strlen(last_search);
+	    /* Set the cursor at the last character of the replacement
+	     * text, so searching will resume after the replacement text.
+	     * Note that current_x might be set to -1 here. */
+#ifndef NANO_SMALL
+	    if (!ISSET(REVERSE_SEARCH))
+#endif
+		current_x += match_len + length_change - 1;
 
-		    if (*beginx > strlen(current->data))
-			*beginx = strlen(current->data);
-		}
-	    }
+	    /* Cleanup */
+	    totsize += length_change;
+	    free(current->data);
+	    current->data = copy;
 
 	    edit_refresh();
 	    set_modified();