ReplaceTextFmt2.vb
''
'' This code is part of GrapeCity Documents for Word samples.
'' Copyright (c) GrapeCity, Inc. All rights reserved.
''
Imports System.Drawing
Imports System.Text
Imports System.Linq
Imports System.Collections.Generic
Imports System.Text.RegularExpressions
Imports GrapeCity.Documents.Word

'' This sample loads an existing document, finds all occurrences
'' of a certain string in it, And replaces that string with another one,
'' also changing the character format of the replacement string.
'' This sample Is almost identical to ReplaceTextFmt
'' but uses PersistentRange instead of Range.
'' Its primary purpose Is to illustrate the differences between
'' Range And PersistentRange.
Public Class ReplaceTextFmt2
    Function CreateDocx() As GcWordDocument
        '' The document to replace text in:
        Dim path = IO.Path.Combine("Resources", "WordDocs", "JsFrameworkExcerpt.docx")
        '' The text to find
        Const tFind = "javascript"
        '' The replacement
        Const tRepl = "ArabicaScroll"

        Dim doc = New GcWordDocument()
        doc.Load(path)

        Dim runs = doc.Body.Runs
        Dim runRanges = New List(Of PersistentRange)(runs.Count)
        For Each run In runs
            runRanges.Add(run.GetPersistentRange())
        Next

        For Each rr In runRanges
            Dim str = rr.Text
            Dim matches = Regex.Matches(str, tFind, RegexOptions.IgnoreCase)
            If matches.Count = 0 Then
                Continue For
            End If

            Dim color = rr.ParentRun.Font.Color.RGB
            rr.Clear()
            Dim pos = 0
            For Each m In matches
                rr.Runs.Add(str.Substring(pos, m.Index - pos)).Font.Color.RGB = color
                rr.Runs.Add(tRepl).Font.Color.RGB = Color.Red
                pos = m.Index + m.Length
            Next
            rr.Runs.Add(str.Substring(pos)).Font.Color.RGB = color

            If Not String.IsNullOrEmpty(rr.Runs.First.GetRange().Text) Then
                Throw New Exception("Unexpected")
            End If
            rr.Runs.First.Delete()

            '' PersistentRange Is kept up to date when the document changes,
            '' so it should be disposed when no longer needed to improve
            '' performance And reduce memory consumption:
            rr.Dispose()
        Next
        '' Not strictky necessary but a good practice:
        runRanges.Clear()

        '' Add a note at the end of the document
        doc.Body.Sections.Last.GetRange().Paragraphs.Add(
            $"GcWord replaced '{tFind}' with '{tRepl}' on {DateTime.Now}.")

        '' Done
        Return doc
    End Function
End Class