This project has moved. For the latest updates, please go here.

Extension method for text replacement keeping the format.

Nov 29, 2012 at 11:41 AM

public static class DocXExtender 
{
    public static void ReplaceFormatedText(this DocX document, string oldText, string newText) 
    {
        int j, k;
        string textToReplace, text, minText = oldText.Split(' ')[0];
        StringBuilder fullText;
        XElement element, next;
        List<XElement> elements, toRemove;
        IEnumerable<Paragraph> paragraphs = from paragraph in document.Paragraphs where paragraph.Text.Contains(oldText) select paragraph;
        foreach (Paragraph paragraph in paragraphs)
        {
            elements = (from elem in paragraph.Xml.Descendants() where elem.Name.LocalName == "t" select elem).ToList();
            for (int i = 0; i < elements.Count(); i++)
            {
                element = elements[i];
                if (element.Value.Contains(oldText))
                {
                    element.Value = element.Value.Replace(oldText, newText);
                }
                else if (element.Value.Contains(minText))
                {
                    k = element.Value.IndexOf(minText);
                    fullText = new StringBuilder();
                    fullText.Append(element.Value);
                    toRemove = new List<XElement>();
                    j = i;
                    do
                    {
                        j++;
                        next = elements[j];
                        toRemove.Add(next);
                        fullText.Append(next.Value);                            
                    }
                    while (fullText.Length < oldText.Length + k);
                    if (fullText.ToString().Contains(oldText))
                    {
                        text = fullText.ToString();
                        newText += text.Substring(text.IndexOf(oldText) + oldText.Length);
                        textToReplace = element.Value.Substring(k);
                        element.Value = element.Value.Replace(textToReplace, newText);
                        for (int l = toRemove.Count - 1; l >= 0; l--)
                            toRemove[l].RemoveNodes();
                        i = j;
                    }
                }
            }
        }
    }
}

Dec 7, 2012 at 4:56 PM

Excellent work!  I made a few tiny adjustments to make it more robust:

Changed:

string textToReplace, text, minText = oldText.Split(' ')[0];
to:

string textToReplace, text, minText = oldText.Substring(0, 1);

This grabs the first character instead of the first word.  When I searched for items starting with symbols like "[" or "{", searching failed because of extra w:t blocks.

Also changed the condition:

while (fullText.Length < oldText.Length + k);
to:

while (fullText.Length < oldText.Length + k && j < elements.Count - 1);
 

Thanks again for your code!