比较 Word 文档中的文本位置

Compare text locations in Word document

我通过用我的值替换模板文档中的一些占位符文本来生成 Word 文档。为此,我使用 GemBox.Document,更具体地说,Find and Replace 示例中的这段代码:

var document = DocumentModel.Load("input.docx");

var firstPlaceholder = document.Content.Find("%Text1%").First();
firstPlaceholder.LoadText("Value 1");

var secondPlaceholder = document.Content.Find("%Text2%").First();
firstPlaceholder.LoadText("Value 2");

document.Save("output.docx");

效果很好。

但现在我有一个场景,其中将替换占位符的值取决于它们的位置,更具体地说,占位符是出现在文档中某个特定段落之前还是之后。

我确实尝试过使用这样的东西:

Paragraph separator = ...

string firstPlaceholderText = "%Text1%";
string separatorText = seperator.Content.ToString();
string wholeDocumentText = document.Content.ToString();

if (wholeDocumentText.IndexOf(firstPlaceholderText) < wholeDocumentText.IndexOf(separatorText))
{
    // The placeholder is before the separator...
}
else
{
    // The placeholder is after the separator...
}

但是,相同的 separatorText 值可能出现在文档的多个位置,因此 string.IndexOf() 对我来说不是一个可行的解决方案。

有没有其他方法可以进行这种比较,或者有其他方法可以确定某些占位符与其他文档元素相比的位置?

试试这个:

static bool IsPositionBefore(ContentPosition position1, ContentPosition position2)
{
    var parentIndexes1 = GetParentIndexes(position1.Parent);
    var parentIndexes2 = GetParentIndexes(position2.Parent);

    int count = Math.Min(parentIndexes1.Count, parentIndexes2.Count);
    for (int i = 0; i < count; i++)
    {
        if (parentIndexes1[i] < parentIndexes2[i])
            return true;

        if (parentIndexes1[i] > parentIndexes2[i])
            return false;
    }

    // Both positions are inside the same parent element.
    var parent = position1.Parent;
    var parentClone = parent.Clone(true);

    string positionMarker1 = "\u0001";
    string positionMarker2 = "\u0002";
    position1.LoadText(positionMarker1);
    position2.LoadText(positionMarker2);

    string parentContent = parent.Content.ToString();
    int positionOffset1 = parentContent.IndexOf(positionMarker1, StringComparison.Ordinal);
    int positionOffset2 = parentContent.IndexOf(positionMarker2, StringComparison.Ordinal);

    parent.Content.Set(parentClone.Content);

    return positionOffset1 < positionOffset2;
}

static IList<int> GetParentIndexes(Element element)
{
    var parentIndexes = new List<int>();

    while (element.Parent != null)
    {
        parentIndexes.Add(element.ParentCollection.IndexOf(element));
        element = element.Parent;
    }

    parentIndexes.Reverse();

    return parentIndexes;
}

另外,下面是如何使用这个 IsPositionBefore 方法:

if (IsPositionBefore(firstPlaceholder.Start, separator.Content.Start))
{
    // The placeholder is before the separator...
}
else
{
    // The placeholder is after the separator...
}

棘手的部分是当两个位置都在同一元素内时如何确定哪个位置在前。

那是因为 ContentPosition 目前没有某种偏移量 API 可以告诉您它在元素中的确切位置。

所以,我正在做的是临时添加两个随机控制字符,检查哪个出现在另一个之前,然后删除它们。

我认为这种方法是安全的,因为 Word 文档不能包含控制字符(Word 应用程序会将它们显示为已损坏),如果您尝试保存包含此类字符的 DocumentModel,则会出现异常。