// determine if this section of text (some portion of one or more paragraphs) has the find what text in it public FindResult FindReplaceCompare(WordRange aRunRange, ref int SearchAreaStart, ref int FoundAreaLength) { FindResult res = FindResult.eNothingFound; string strInput = aRunRange.Text; if (String.IsNullOrEmpty(strInput) || (m_aECRegex == null)) { return(res); } // otherwise 'convert' it to see if the 'Find what' string is in it string strOutput = m_aECRegex.Convert(strInput); // if the input string is different from the output string, then the FindWhat string was found. if (strInput != strOutput) { #if !DefineToNotUseSplitAndConvert // The way the convert works is that it will replace each instance of the input string that matches // the FindWhat syntax (i.e. there may be more than one replacement we have to deal with). // here's the problem: if there was more than one replacment, then I really can't tell what portion // of the FindWhat text each replacement goes with. Consider the string "ababbbbbabb". If the 'Find // what' string is "ab+", then it breaks up to: "ab", "abbbbb", and "abb", but if these three are // right in a row and the replacement is "", then the resulting strOutput will be <delim><delim>... // repeated 3 times. So there's no way to tell which portion of the input text corresponds to which // portion of the output text. My original stab at it just treated them evenly and divide by the // number of consecutive replacements... this works if the 'FindWhat' is something like "ab". But all // bets are off if the user uses the "+" (eat-em-up) expression code. // I think the only solution is to always only deal with a single replacement... So... if we have more // than one match in a particular output (which we can tell by the Length of astrSegments), do a binary // search until we have only one. string[] astrSegments = GetFirstReplacementSplitArray(ref strInput, ref strOutput); // get the index to the first character of the replacement (which is the same as the first character // of the 'Find what' string as well). int nIndex = astrSegments[0].Length; // remember this so we pick up here later SearchAreaStart += nIndex; if (nIndex > 0) { aRunRange.Start = SearchAreaStart; } // the replacement string is easy. It's just whatever's in the one'th element of the Split array. string strReplacementString = astrSegments[1]; // There might be some stuff between the end of the replacement and the end of the input string. string strStuffFollowingMatch = astrSegments[2]; // may be null // get the index to the end of the 'Find what' string int nEndOfFindWhatSelection; if (String.IsNullOrEmpty(strStuffFollowingMatch)) { nEndOfFindWhatSelection = strInput.Length; } else { nEndOfFindWhatSelection = strInput.Length - strStuffFollowingMatch.Length; } #else // this could probably be done more elegantly with Split rather than what I do in the #else case string[] astrSegments = strOutput.Split(m_achDelimiter); // must be odd (before, ||: replace, following :||), where any or all can be null int nTotalSegments = astrSegments.Length; System.Diagnostics.Debug.Assert((nTotalSegments % 2) == 1); // get the index to the first character of the replacement (which is the same as the first character // of the 'Find what' as well). int nIndex = astrSegments[0].Length; // remember this so we pick up here later SearchAreaStart += nIndex; if (nIndex > 0) { aRunRange.Start = SearchAreaStart; } // the replacement string is easy. It's just whatever's in the 1st element of the Split array. // but we have to figure out what the 'Find what' text is so that we can select it (so we can replace // it). This is not so easy, because it could be anything and not just a string of text like in a normal // find. string strReplacementString = astrSegments[1]; // Between the end of the first replacement and the beginning of the next (if multiple replacments) // is a string which should match something in the original, which we can search for string strStuffFollowingMatch = astrSegments[2]; // may be null int nEndOfFindWhatSelection; if (String.IsNullOrEmpty(strStuffFollowingMatch)) { // If the 'Find what' is repeated twice in a row, then the stuff in-between the two instances of // replacement text will be null. // Detect this by looking at the length of the even number string array elements (2, 4, etc), // which are the segments following the replacements. This tells us what we have to divide by // to get the proportion for only one find. int nNumReplacmentsInARow = 1; int nNextReplacementIndex = 2; nTotalSegments--; while ((nNextReplacementIndex < nTotalSegments) && String.IsNullOrEmpty(astrSegments[nNextReplacementIndex])) { nNumReplacmentsInARow++; nNextReplacementIndex += 2; } if (nNextReplacementIndex < astrSegments.Length) { strStuffFollowingMatch = astrSegments[nNextReplacementIndex]; } int numerator; if (String.IsNullOrEmpty(strStuffFollowingMatch)) { numerator = strInput.Length; } else { numerator = strInput.IndexOf(strStuffFollowingMatch, nIndex + 1); } nEndOfFindWhatSelection = ((numerator - nIndex) / nNumReplacmentsInARow) + nIndex; } else { nEndOfFindWhatSelection = strInput.IndexOf(strStuffFollowingMatch, nIndex + 1); } /* * int nIndex = strOutput.IndexOf(m_achDelimiter[0]); * System.Diagnostics.Debug.Assert(nIndex != -1); * SearchAreaStart += nIndex; * if (nIndex > 0) * aRunRange.Start = SearchAreaStart; * * int nEndOfReplacement = strOutput.IndexOf(m_achDelimiter[0], nIndex + 1); * System.Diagnostics.Debug.Assert(nEndOfReplacement != -1); * * // the replacement string is what's between these two * string strReplacementString = strOutput.Substring(nIndex + 1, (nEndOfReplacement - nIndex - 1)); * * // now the complicated part. Between the end of the first replacement and the next * // one is a string which should match something in the original. But if the replacement * // were null, then it could be the very next character... * // This also handles the situation where there may be several "found whats" * int nNumReplacmentsInARow = 1; * int nNextIndex = nEndOfReplacement + 1; * while ((nNextIndex < strOutput.Length) && (strOutput[nNextIndex] == m_achDelimiter[0])) * { * nNumReplacmentsInARow++; * nEndOfReplacement = strOutput.IndexOf(m_achDelimiter[0], nNextIndex + 1); * nNextIndex = nEndOfReplacement + 1; * } * * if (nNextIndex < strOutput.Length) * { * nEndOfReplacement = strOutput.IndexOf(m_achDelimiter[0], nNextIndex + 1); * if (nEndOfReplacement == -1) * nEndOfReplacement = strOutput.Length; * } * else if (nNextIndex == strOutput.Length) * nNextIndex--; * * string strStuffFollowingMatch = strOutput.Substring(nNextIndex, nEndOfReplacement - nNextIndex); * * nEndOfFindWhatSelection = ((strInput.Length - nIndex) / nNumReplacmentsInARow) + nIndex; * if (!String.IsNullOrEmpty(strStuffFollowingMatch)) * { * nEndOfFindWhatSelection = strInput.IndexOf(strStuffFollowingMatch, nIndex + 1) / nNumReplacmentsInARow; * } */ #endif // !UseSplitToFindReplacements FoundAreaLength = nEndOfFindWhatSelection - nIndex; aRunRange.End = SearchAreaStart + FoundAreaLength; // if we're doing ReplaceAll or Replace when the FindWhat string has been found... System.Diagnostics.Debug.Assert(FormButton != FormButtons.Cancel); // means it wasn't initialized if (!DontReplaceOnNextFind && ((ReplaceAll) || ((FormButton == FormButtons.ReplaceOnce) && (nIndex == 0)))) { if (FormButton == FormButtons.ReplaceOnce) { DontReplaceOnNextFind = true; // so we do a virtual find next after this } // this means replace the word in situ, with what was converted ReplaceText(aRunRange, strReplacementString); NumOfReplacements++; // start the next search after this replaced value string strReplacedText = aRunRange.Text; // this may not be exactly the same as strReplace (e.g. after replacing final '\r') if (!String.IsNullOrEmpty(strReplacedText)) { FoundAreaLength = strReplacedText.Length; SearchAreaStart += FoundAreaLength; } res = FindResult.eReplaceFound; } else { // select just the search string and return as if cancelled so the outer loop can prompt for it. IsFound = true; // select the FindWhat text found aRunRange.Select(); res = FindResult.eFindFound; } } else if (FormButton == FormButtons.ReplaceOnce) { // otherwise, if the user clicked ReplaceOnce and we didn't find it right away, // then change it to function like Find instead. DontReplaceOnNextFind = true; // so we do a virtual find next after this } return(res); }