Replace method with \r (hard return character) for text in table cell and outside of it

Hello,
Im currently working on replacing some text in docx files and have faced next issue:

Lets imagine I want to replace “12345” string to some text “some\rtext with\rhard returns”
If this text is not in table cell - all works great, but if not - all \r replaced by another symbol and as result im not getting what im expect. Maybe you could help me with this please?

Details:
aspose-words 17.5 - newest version supported by my current license
files with example attached

Thanks in advance,
Serhii

template.zip (9.6 KB)
got.zip (9.1 KB)
expected.zip (9.5 KB)

    final String basePath = "C:\\test\\";
    final String templateName = "template.docx";
    final String outputName = "output.docx";
    final String replaceStr = "[0-9]+";

     License license = new License();
     license.setLicense("C:\\apps\\asposeLicense\\Aspose.Words.lic");

    Document doc = new Document(basePath + templateName);

    IReplacingCallback replacingCallback = replacingArgs -> {
        Run matchNode = (Run)replacingArgs.getMatchNode();
        matchNode.setText("Just\rSome\tLine\rWith hard returns\r");
        return ReplaceAction.SKIP;
    };

    doc.getRange().replace(Pattern.compile(replaceStr), replacingCallback, false);

    doc.save(basePath + outputName);

@Serhii,

Thanks for your inquiry. Please use the latest version of Aspose.Words for Java 18.4 and new Range.Replace method (Regex, String, FindReplaceOptions). In your case, you need to use special meta-characters to specify breaks; &p for paragraph break and &l for manual line break.

Please use one of the following code example to get the desired output.

final String templateName = MyDir + "template.docx";
final String outputName = MyDir + "output.docx";
final String replaceStr = "[0-9]+";

Document doc = new Document(templateName);
  
FindReplaceOptions options = new FindReplaceOptions();
options.setMatchCase(true);
options.setFindWholeWordsOnly(false);
doc.getRange().replace(Pattern.compile(replaceStr), "Just\rSome\tLine\rWith hard returns\r".replace("\r", "&p") , options);

doc.save(outputName);

final String templateName = MyDir + "template.docx";
final String outputName = MyDir + "output.docx";
final String replaceStr = "[0-9]+";

Document doc = new Document(templateName);

IReplacingCallback replacingCallback = replacingArgs -> {
    Run matchNode = (Run)replacingArgs.getMatchNode();
    replacingArgs.setReplacement("Just\rSome\tLine\rWith hard returns\r".replace("\r", "&p"));
    return ReplaceAction.REPLACE;
};

FindReplaceOptions options = new FindReplaceOptions();
options.setReplacingCallback(replacingCallback);
options.setMatchCase(true);
options.setFindWholeWordsOnly(false);
doc.getRange().replace(Pattern.compile(replaceStr), "" , options);

doc.save(outputName);

Thanks for answer, it is working well.

But maybe there is way to also handle multiple runs at the same time?

Thank you

@Serhii,

Thanks for your inquiry. You can insert multiple Run nodes into document in IReplacingCallback.Replacing method. Could you please share some more detail about your query along with input and expected output documents? We will then provide you more information on it.

Hi Tahir, thank you very much for your prompt responses. Serhii and I working for the same client trying to solve this issue.
We have updated the lib to aspose-words-17.9-jdk16.jar (latest for our license).
Unfortunately, it has not solved the issue.
We have been using a custom implementation of IReplacingCallback. This implementation is well tested and thus we would like to avoid major changes to it if possible.
It works nicely except that issue with replacing text in Table Cells when text like this: “1st paragraph\r2nd paragraph”, is not actually split into 2 Paragraph Nodes when it’s used for replacing in a Table Cell.
Our IReplacingCallback implementation is using Run.setText(String) along with return ReplaceAction.SKIP, as in the example:

Pattern regex = Pattern.compile("<<12345>>", Pattern.CASE_INSENSITIVE);

    document.getRange().replace(regex, new IReplacingCallback() {
        // Simple test - assuming that the match comes in a single Run
        @Override
        public int replacing(ReplacingArgs replacingArgs) throws Exception {
            Run matchNode = (Run)replacingArgs.getMatchNode();

            matchNode.setText("Line 1 before line break \r Line 2 after break");  // is not converted to Paragraph when in Cell; not even in 17.9
            //matchNode.setText("Line 1 before line break &p Line 2 after break");    // &p is not replaced - neither was with 16.17 nor in 17.9

            return ReplaceAction.SKIP;
        }
    }, false);
    document.save(generatedDocumentsDirectory + documentName);

And the problem is not in using the now deprecated replace method - this does not work correctly either:

        FindReplaceOptions options = new FindReplaceOptions(new IReplacingCallback() {
        // Simple test - assuming that the match comes in a single Run
        @Override
        public int replacing(ReplacingArgs replacingArgs) throws Exception {
            Run matchNode = (Run)replacingArgs.getMatchNode();

            matchNode.setText("Line 1 before line break \r Line 2 after break");  // is not converted to Paragraph when in Cell
            //matchNode.setText("Line 1 before line break &p Line 2 after break");    // &p is not replaced

            return ReplaceAction.SKIP;
        }
    });

    options.setDirection(FindReplaceDirection.BACKWARD);
    options.setMatchCase(false);
    options.setFindWholeWordsOnly(false);

    document.getRange().replace(regex, "", options);

So the problem seems to be in using Run.setText. The reason we are using setText is because we have created our own method that “merges” multiple Run nodes that contain matched text into a single Run object on which we invoke setText. It works well except for when used to replace text in Tables.
Can you please provide further suggestions based on this information?

@VitaliT,

Thanks for your inquiry. In case, you do not want to use meta-characters, we suggest you following solution.

  1. Check if the matched node is child node of table’s cell.
  2. If yes, please move the cursor to the Run node.
  3. Insert the desired content using DocumentBuilder.write method.
  4. Remove the matched node.

Please check the following code example. Hope this helps you.

    final String templateName = MyDir + "template.docx";
    final String outputName = MyDir + "output.docx";
    final String replaceStr = "[0-9]+";

    Document doc = new Document(templateName);
    IReplacingCallback replacingCallback = replacingArgs -> {
        Run matchNode = (Run)replacingArgs.getMatchNode();

    if(matchNode.getAncestor(NodeType.CELL) != null)
    {
        DocumentBuilder builder = new DocumentBuilder((Document)matchNode.getDocument());
        builder.moveTo(matchNode);
        builder.write("Just\rSome\tLine\rWith hard returns\r");
        matchNode.remove();
    }
    else
        matchNode.setText("Just\rSome\tLine\rWith hard returns\r");
    return ReplaceAction.SKIP;
    };

    doc.getRange().replace(Pattern.compile(replaceStr), replacingCallback, false);
    doc.save(MyDir + "output.docx");

Tahir, thank you very much for your help. We’re testing both of your suggestions in QA now.

@VitaliT,

Please feel free to ask if you have any question about Aspose.Words, we will be happy to help you.