Hello Team,
I am using Find and Replace a specific regex text in a Word document and replace it with content from an Excel file. I’ve also created a sample project where you can add your license. However, when I upload the Word document, the replacement happens in the wrong location. Can you help me resolve this issue and ensure the replacements are correctly placed in all cases?
AsposeExcelReplacement.zip (201.3 KB)
INPUT-DOC.docx (16.1 KB)
OUTPUT-DOC.docx (14.8 KB)
@KeerthanaRamesh214 As I can see in your code you use the following:
var builder = new DocumentBuilder(args.MatchNode.Document as Document);
builder.MoveTo(args.MatchNode);
it is not mandatory that ReplacingArgs.MatchNode
contains the exact match. The match can span several nodes, or can contain other text. You can change your IReplacingCallback
like this:
public class ReplacingCallbackWrapWithHyperlink : IReplacingCallback
{
public ReplaceAction Replacing(ReplacingArgs args)
{
Document doc = (Document)args.MatchNode.Document;
List<Run> matchedRuns = GetMatchedRuns(args);
DocumentBuilder builder = new DocumentBuilder(doc);
// Move DocumentBuilder to the matched text and insert hyperlink
builder.MoveTo(matchedRuns[0]);
builder.Font.StyleIdentifier = StyleIdentifier.Hyperlink;
builder.InsertHyperlink(args.Match.Value, args.Replacement, false);
// Delete matched runs
foreach (Run run in matchedRuns)
run.Remove();
// Signal to the replace engine to do nothing because we have already done all what we wanted.
return ReplaceAction.Skip;
}
private static List<Run> GetMatchedRuns(ReplacingArgs args)
{
// This is a Run node that contains either the beginning or the complete match.
Node currentNode = args.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 (args.MatchOffset > 0)
currentNode = SplitRun((Run)currentNode, args.MatchOffset);
// This array is used to store all nodes of the match for further deleting.
List<Run> runs = new List<Run>();
// Find all runs that contain parts of the match string.
int remainingLength = args.Match.Value.Length;
while (
remainingLength > 0 &&
currentNode != null &&
currentNode.GetText().Length <= remainingLength)
{
runs.Add((Run)currentNode);
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((Run)currentNode);
}
return runs;
}
private static Run SplitRun(Run run, int position)
{
Run afterRun = (Run)run.Clone(true);
run.ParentNode.InsertAfter(afterRun, run);
afterRun.Text = run.Text.Substring(position);
run.Text = run.Text.Substring((0), (0) + (position));
return afterRun;
}
}
As you can see in this example the code collects all runs that represent the match. You should modify the example to insert the required content. The above provided implementation demonstrates the basic technique.
How can I apply this is my code sample as I have different logic of inserting content can you help me with code if possible. As its not clear where my replacement logic will go.
@KeerthanaRamesh214 Instead of the following two lines of code:
var builder = new DocumentBuilder(args.MatchNode.Document as Document);
builder.MoveTo(args.MatchNode);
you should use the following code:
Document doc = (Document)args.MatchNode.Document;
List<Run> matchedRuns = GetMatchedRuns(args);
DocumentBuilder builder = new DocumentBuilder(doc);
// Move DocumentBuilder to the matched text and insert hyperlink
builder.MoveTo(matchedRuns[0]);
See GetMatchedRuns
method in the above provided IReplacingCallback
.
I used the same way and getting {“Specified argument was out of the range of valid values. (Parameter ‘key’)”} in the above project can you help me out her to resolve this issue. Also in the sample project this is happening at return ReplaceAction.Replace;
@KeerthanaRamesh214 ReplaceAction.Replace
should be used when value is actually replaced. but you are performing a custom action in IReplacingCallback
and insert content using DocumentBuilder
. In this case you should use ReplaceAction.Skip
, since no actual value replacing is required in your case and all the work is already done by DocumentBuilder
.
Then where can I do the replace because if I didn’t use the replacement value was also there
I have attached the document generated see the replacement was not happening instead its just inserting in correct location that is good
OUTPUT_WITH SKIP.docx (14.9 KB)
Ignore I just forgot to remove the runs after the insertion Its working fine Thank you.
1 Like
@KeerthanaRamesh214 It is perfect that you managed to resolve the problem.
1 Like