Hi, I am a rookie user of the demo version of Aspose.word, looking to replace MS in various .net applications.
I wish to use find/replace on known text rather than mailmerge fields, but have hit a slight snagette. It looks as though the replace text cannot span over more than 1 line, but I need to insert paragraphs - formatted addresses and one -off inserts in standard letter templates.
I have tried using CR, LF and CRLF combinations. plus a few common escape code sequences, but with no success
Have I missed something obvious in my code, or is this a limitation of replace ?
Many thanks,
MichaelB
Hi Michael,
Thank you for your interest in Aspose.Word.
At the moment replace is limited to replacing text within a single paragraph. The API documentation mentions this in the description of the Range.Replace method:
An exception is thrown if a captured or replacement string contain one or more special characters: paragraph break, cell break, section break, field start, field separator, field end, inline picture, drawing object, footnote.
We will support replace across multiple paragraphs later, in a few months. The reason replace is limited at the moment is purely technical - the text is stored as a tree-like model and replacing across paragraph requires some non-trivial node splitting and joining.
You might be able to workaround and make it work for you because you can navigate through all document tree nodes, modify, insert and remove them programmatically.
Hello
We have the same problem, we want to replace multiple lines of formatted text in a word document with new text (which may have more lines than the source text).
New versions of Aspose.Words have released within the 3 years, but the feature to replace multiple lines in one step seems not yet to be implemented, as we can see in the given Exception:The replace string cannot contain special or break characters. at ՞.ⱔ.set_ⱖ(String ) at Aspose.Words.Range.Replace(String oldValue, String newValue, Boolean isMatchCase, Boolean isMatchWholeWord)
We have the following situation:Given is a word Template with placeholders (variables). The variables should be replaced during runtime:
The Example shows a formatted text fragment in a word template:
__Loop(CommercialOrder.ContactList)__
Street: __Simple(Address.street)__
FirstName: __Simple(firstName)__
__Loop(TypeList)__
Contact Type: __Simple(.)__
__/Loop(TypeList)__
__/Loop(CommercialOrder.ContactList)__
The result after the Replacement looks like (e.g. when there are 2 Contacts defined):
Street: Amselweg 13
FirstName: Christian
Contact Type: Projektleiter
Street: Finkenweg 22
FirstName: Manfred
Contact Type: Programmierer
Cause the source and output texts are multi line (formatted) texts, Aspose.Words can’t replace it.
The Replacement process works fine for Outlook Mails by using Aspose.Network, but we have to implement it for Word Documents too.When we use a RTF Document template without the Aspose.Words library, it woks fine, but RTF has some major disadvantages.
Does there exist a way to replace multiple lines of formatted text in a word document?
Thank you for your suggestions & Kind RegardsChristian Broennimann
Hi
Thanks for your request. Unfortunately you can replace multiple paragraphs. But I think in your case it better to use mail merge feature instead replacing text. Please see the following link for more information.
For example see the following code, attached template and output document:
//Create dummy datasource
DataTable info = new DataTable("Info");
info.Columns.Add("Street");
info.Columns.Add("FirstName");
info.Columns.Add("ContactType");
//Add data
info.Rows.Add(new object[] { "Amselweg 13", "Christian", "Projektleiter" });
info.Rows.Add(new object[] { "Finkenweg 22", "Manfred", "Programmierer" });
//Open template
Document doc = new Document(@"Test205\in.doc");
//Execute mail merge with regions
doc.MailMerge.ExecuteWithRegions(info);
//Save output document
doc.Save(@"Test205\out.doc");
Hello
Thank you for the example. We could solve the problem with your suggestion!
Kind Regards,
Christian Brönnimann
Hi,
I am trying to replace some text in a document with a multi-line address like the one below keeping the format/style of the original text. Is there a way or work around to do this?
Example:
123 Maple Street
Toronto, ON
M1M1M1
Thank you.
Hi
Thanks for your request. You can achieve this using ReplaceEvaluator. Please see the following link for more information.
Hope this helps.
Best regards.
Hi Rodion,
Hi Rodion,
Thanks for your patience. Firstly, I would suggest you please read the following articles that outlines Document Tree Navigation and DOM:
Aspose.Words Document Object Model
In your case, I suggest you please insert bookmarks before and after of following lines of text. After inserting bookmark for multi lines of text, you can easily remove these contents and add new text at the same place.
Following code snippet does the followings:
- Finds the text ( start and end nodes ) and insert bookmarks before and after above lines of text.
- Remove the text between inserted bookmarks
- Add new text
- At the end remove the inserted bookmarks
Document doc = newDocument(MyDir + “in.docx”);
DocumentBuilder builder = new DocumentBuilder(doc);
ReplaceMultiLineEval replace = new ReplaceMultiLineEval();
replace.findtext = @"\[\[LOW_INCOME_SUBSIDY_RIDER";
replace.bookmark = "bm1";
replace.isStart = true;
Regex regex = new Regex(replace.findtext, RegexOptions.IgnoreCase);
doc.Range.Replace(regex, replace, true);
replace.findtext = @"coinsurance.end\]\]";
replace.bookmark = "bm2";
replace.isStart = false;
Regex regex2 = new Regex(replace.findtext, RegexOptions.IgnoreCase);
doc.Range.Replace(regex2, replace, true);
builder.MoveToBookmark("bm1");
Node start = builder.CurrentNode;
builder.MoveToBookmark("bm2");
Node end = builder.CurrentNode;
Node currentNode = start;
ArrayList nodes = new ArrayList();
while (currentNode != end)
{
if (currentNode.NodeType == NodeType.Run)
{
// ((Run)currentNode).Font.Color = Color.Yellow;
nodes.Add(currentNode);
}
currentNode = currentNode.NextPreOrder(doc);
}
foreach (Run run in nodes)
{
run.Remove();
}
builder.MoveToBookmark("bm1");
builder.Writeln("New Text");
doc.Range.Bookmarks["bm1"].Remove();
doc.Range.Bookmarks["bm2"].Remove();
// Save the output document.
doc.Save(MyDir + "Out.docx");
public class ReplaceMultiLineEval : IReplacingCallback
{
public string findtext { get; set; }
public string bookmark { get; set; }
public Boolean isStart { get; set; }
ReplaceAction IReplacingCallback.Replacing(ReplacingArgs e)
{
// This is a Run node that contains either the beginning or the complete match.
Node currentNode = e.MatchNode;
DocumentBuilder builder = new DocumentBuilder((Document)e.MatchNode.Document);
if (isStart == false)
{
Run run = new Run((Document)e.MatchNode.Document, "");
Paragraph paragraph = (Paragraph)currentNode.GetAncestor(NodeType.Paragraph);
paragraph.InsertAfter(run, currentNode);
builder.MoveTo(run);
builder.StartBookmark(bookmark);
builder.EndBookmark(bookmark);
}
else
{
builder.MoveTo(currentNode);
builder.StartBookmark(bookmark);
builder.EndBookmark(bookmark);
}
return ReplaceAction.Skip;
}
}
Please read following documentation links for your kind reference.
Find and Replace
How to Find and Highlight Text
If you still face problem, please share input and expected output document with us. We will then provide you more information about your query along with code.
Cannot perform further replacements since the document has been changed.
on line - doc.Range.Replace(regex, replace, true);
Thanks for your inquiry. Please use Range.Replace Method (Regex, String, FindReplaceOptions) method to replace all occurrences of a character pattern specified by a regular expression with another string. We suggest you please upgrade to the latest version of Aspose.Words for .NET 17.11.
Please refer to the following article.
Find and Replace
Thanks for your reply, the above works fine for single line text but fails to replace multi line text. Essentially the solution that you have given here is exactly what I am looking for, however it doesn’t work with Version 17.10.
1. Finds the text (start and end nodes) and insert bookmarks before and after above lines of text.
2. Remove the text between inserted bookmarks
3. Add new text
4. At the end remove the inserted bookmarks
Here is a quick glance of what I want to achieve;
I have predefined tags in the word document, I want to remove everything including lines, special characters etc that falls in between those tags, for example
[ToBeRemoved]
– remove this 1
– remove this 2
– remove this 3
[/ToBeRemoved]
I want to remove the above text which is in between the [ToBeRemoved][/ToBeRemoved] tags including the tags itself.
Can you provide me the best possible solution for this or a sample?
Thanks for your inquiry. Please use the following code example to achieve your requirement. Hope this helps you.
Document doc = new Document(MyDir + "in.docx");
FindReplaceOptions options = new FindReplaceOptions();
options.ReplacingCallback = new FindAndInsertBookmark("bookmark", true);
doc.Range.Replace(@"[ToBeRemoved]", "", options);
options.ReplacingCallback = new FindAndInsertBookmark("bookmark", false);
doc.Range.Replace(@"[/ToBeRemoved]", "", options);
doc.Range.Bookmarks["bookmark"].Text = "";
DocumentBuilder builder = new DocumentBuilder(doc);
builder.MoveToBookmark("bookmark");
builder.Writeln("New text");
doc.Range.Bookmarks["bookmark"].Remove();
doc.Save(MyDir + "output.docx");
public class FindAndInsertBookmark : IReplacingCallback
{
string bmname;
Boolean isStart;
DocumentBuilder builder;
public FindAndInsertBookmark(string bmname, Boolean isStart)
{
this.bmname = bmname;
this.isStart = isStart;
}
ReplaceAction IReplacingCallback.Replacing(ReplacingArgs e)
{
// This is a Run node that contains either the beginning or the complete match.
Node currentNode = e.MatchNode;
if (builder == null)
builder = new DocumentBuilder((Document)currentNode.Document);
// 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);
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);
}
if (isStart)
{
Run run = (Run)runs[runs.Count - 1];
run.ParentNode.InsertAfter(new BookmarkStart(run.Document, bmname), run);
}
else
{
Run run = (Run)runs[0];
run.ParentNode.InsertBefore(new BookmarkEnd(run.Document, bmname), run);
}
// Signal to the replace engine to do nothing because we have already done all what we wanted.
return ReplaceAction.Skip;
}
/// <summary>
/// Splits text of the specified run into two runs.
/// Inserts the new run just after the specified run.
/// </summary>
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;
}
}