Free Support Forum - aspose.com

Error in Document.Range.Replace

Hi,


I have a problem que use this method (Document.Range.Replace) because the new text sometimes contains a carry return.

Are there any solution for this?

Thanks for all.

Best regards,

Hi

Thanks for your request. There is not direct method to replace text with special characters, however, you can achieve this using IReplacingCallback. I created a simple code example that demonstrates the technique:

[Test]

public void Test001()

{

Document doc = new Document(@"Test001\in.doc");

doc.Range.Replace(new Regex(@"test"), new ReplaceEvaluatorFindAndInsertText("Here you can insert any text\nWith special characters you want\fall of them will be properly handled"), false);

doc.Save(@"Test001\out.doc");

}

private class ReplaceEvaluatorFindAndInsertText : IReplacingCallback

{

public ReplaceEvaluatorFindAndInsertText(string text)

{

mText = text;

}

///

/// This method is called by the Aspose.Words find and replace engine for each match.

/// This method replaces the match string, even if it spans multiple runs.

///

ReplaceAction IReplacingCallback.Replacing(ReplacingArgs e)

{

// This is a Run node that contains either the beginning or the complete match.

Node currentNode = e.MatchNode;

// The first (and may be the only) run can contain text before the match,

// in this case it is necessary to split the run.

if (e.MatchOffset > 0)

currentNode = SplitRun((Run)currentNode, e.MatchOffset);

// This array is used to store all nodes of the match for further removing.

ArrayList runs = new ArrayList();

// Find all runs that contain parts of the match string.

int remainingLength = e.Match.Value.Length;

while (

(remainingLength > 0) &&

(currentNode != null) &&

(currentNode.GetText().Length <= remainingLength))

{

runs.Add(currentNode);

remainingLength = remainingLength - currentNode.GetText().Length;

// Select the next Run node.

// Have to loop because there could be other nodes such as BookmarkStart etc.

do

{

currentNode = currentNode.NextSibling;

}

while ((currentNode != null) && (currentNode.NodeType != NodeType.Run));

}

// Split the last run that contains the match if there is any text left.

if ((currentNode != null) && (remainingLength > 0))

{

SplitRun((Run)currentNode, remainingLength);

runs.Add(currentNode);

}

// Create Document Buidler aond insert text

DocumentBuilder builder = new DocumentBuilder(e.MatchNode.Document as Document);

builder.MoveTo((Run)runs[runs.Count - 1]);

builder.Write(mText);

// Now remove all runs in the sequence.

foreach (Run run in runs)

run.Remove();

// Signal to the replace engine to do nothing because we have already done all what we wanted.

return ReplaceAction.Skip;

}

///

/// Splits text of the specified run into two runs.

/// Inserts the new run just after the specified run.

///

private static Run SplitRun(Run run, int position)

{

Run afterRun = (Run)run.Clone(true);

afterRun.Text = run.Text.Substring(position);

run.Text = run.Text.Substring(0, position);

run.ParentNode.InsertAfter(afterRun, run);

return afterRun;

}

private string mText;

}

Hope this helps. Please let me know if you need more information. I will be glad to help you.

Best regards,

Hi,


I use this code but I have a new problem:

e.matchNode is not the correct node and the replace is wrong.

I attach a document with this example and it is the example code:

Private Sub TestReplace()
Dim d As Document

d = New Document(“d:\pruebas\replace.docx”)
d.Range.Replace(New Regex("[RAW.SES.PRO.LIS.TITULO]"), New ReplaceEvaluatorFindAndInsertText(“First sentence” & vbCrLf & “Second sentence”), False)
d.Save(“d:\pruebas\replace2.docx”)
End Sub

Public Class ReplaceEvaluatorFindAndInsertText
Implements IReplacingCallback

Private _Text As String

Public Sub New(ByVal Text As String)
_Text = Text
End Sub

Public Function Replacing(e As Aspose.Words.ReplacingArgs) As Aspose.Words.ReplaceAction Implements Aspose.Words.IReplacingCallback.Replacing

If _Text.Contains(vbCrLf) Then

'Este es un Run node que contiene el comienzo o bien la coincidencia completa.
Dim currentNode As Node = e.MatchNode

'El primero (y quizás sea el único) run puede contener texto antes de la coincidencia,
'en este caso, es necesario separar el run
If e.MatchOffset > 0 Then
currentNode = SplitRun(CType(currentNode, Run), e.MatchOffset)
End If

'Este array es usado para almacenar todos los nodos de la coincidencia.
Dim runs As ArrayList = New ArrayList

'Encuentra todos los runs node que contienen partes de la cadena de la coincidencia
Dim remainingLength As Integer = e.Match.Value.Length

While (remainingLength > 0 AndAlso currentNode IsNot Nothing AndAlso currentNode.GetText.Length <= remainingLength)
runs.Add(currentNode)
remainingLength = remainingLength - currentNode.GetText.Length
End While

'Seleccionamos el siguiente Run node.
'Realizamos el bucle porque podemos encontrar otros tipos de nodo como Bookmarks etc…
Do
currentNode = currentNode.NextSibling
Loop While currentNode IsNot Nothing AndAlso currentNode.NodeType <> NodeType.Run

'Separar el ultimo Run node que contiene la coincidencia si hay algun texto a la izquierda
If currentNode IsNot Nothing AndAlso remainingLength > 0 Then
SplitRun(currentNode, remainingLength)
runs.Add(currentNode)
End If

'Crear un document builder y insertar el texto
Dim builder As DocumentBuilder = New DocumentBuilder(e.MatchNode.Document)
If runs.Count > 0 Then
builder.MoveTo(runs(runs.Count - 1))
Else
builder.MoveTo(e.MatchNode)
End If
builder.Write(_Text)

'Ahora borramos todos los Run nodes in secuencia
For Each Run As Run In runs
Run.Remove()
Next

'Indicamos al motor de reemplazo de Aspose de no hacer nada porque en este proceso ya se ha realizado
‘todas las tareas que necesitabamos en el reemplazo.

End If

Return ReplaceAction.Stop
End Function

‘’’
‘’'Separa el texto de un Run node en concreto en dos Run nodes.
‘’‘Inserta un nuevo Run node justo después del especificado Run node.
‘’’
Private Function SplitRun(run As Run, position As Integer) As Run
Dim afterRun As Run = run.Clone(True)
afterRun.Text = run.Text.Substring(position)
run.Text = run.Text.Substring(0, position)
run.ParentNode.InsertAfter(afterRun, run)

Return afterRun
End Function
End Class

Hi

Thanks for your request. Here is code I used for testing and all works fine on my side:

_

Public Sub Test001()

Dim doc As New Document("C:\Temp\replace.docx")

doc.Range.Replace(New Regex(Regex.Escape("[RAW.SES.PRO.LIS.TITULO]")), New ReplaceEvaluatorFindAndInsertText("First sentence" & vbCrLf & "Second sentence"), False)

doc.Save("C:\Temp\out.docx")

End Sub

Private Class ReplaceEvaluatorFindAndInsertText

Implements IReplacingCallback

Public Sub New(ByVal text As String)

mText = text

End Sub

'''

''' This method is called by the Aspose.Words find and replace engine for each match.

''' This method replaces the match string, even if it spans multiple runs.

'''

Private Function IReplacingCallback_Replacing(ByVal e As ReplacingArgs) As ReplaceAction Implements IReplacingCallback.Replacing

' This is a Run node that contains either the beginning or the complete match.

Dim currentNode As Node = e.MatchNode

' The first (and may be the only) run can contain text before the match,

' in this case it is necessary to split the run.

If e.MatchOffset > 0 Then

currentNode = SplitRun(CType(currentNode, Run), e.MatchOffset)

End If

' This array is used to store all nodes of the match for further removing.

Dim runs As New ArrayList()

' Find all runs that contain parts of the match string.

Dim remainingLength As Integer = e.Match.Value.Length

Do While (remainingLength > 0) AndAlso (currentNode IsNot Nothing) AndAlso (currentNode.GetText().Length <= remainingLength)

runs.Add(currentNode)

remainingLength = remainingLength - currentNode.GetText().Length

' Select the next Run node.

' Have to loop because there could be other nodes such as BookmarkStart etc.

Do

currentNode = currentNode.NextSibling

Loop While (currentNode IsNot Nothing) AndAlso (currentNode.NodeType <> NodeType.Run)

Loop

' Split the last run that contains the match if there is any text left.

If (currentNode IsNot Nothing) AndAlso (remainingLength > 0) Then

SplitRun(CType(currentNode, Run), remainingLength)

runs.Add(currentNode)

End If

' Create Document Buidler aond insert text

Dim builder As New DocumentBuilder(e.MatchNode.Document)

builder.MoveTo(DirectCast(runs(runs.Count - 1), Run))

builder.Write(mText)

' Now remove all runs in the sequence.

For Each run As Run In runs

run.Remove()

Next run

' Signal to the replace engine to do nothing because we have already done all what we wanted.

Return ReplaceAction.Skip

End Function

'''

''' Splits text of the specified run into two runs.

''' Inserts the new run just after the specified run.

'''

Private Shared Function SplitRun(ByVal run As Run, ByVal position As Integer) As Run

Dim afterRun As Run = CType(run.Clone(True), Run)

afterRun.Text = run.Text.Substring(position)

run.Text = run.Text.Substring(0, position)

run.ParentNode.InsertAfter(afterRun, run)

Return afterRun

End Function

Private Shared mText As String

End Class

Best regards,