【问题标题】:Word.Range : Move Range index in the formatted text that corresponds to the plain textWord.Range :在格式文本中移动范围索引,对应于纯文本
【发布时间】:2024-06-10 23:45:02
【问题描述】:

我需要分析 Word 文档的文本,并在分析器检测到的文本范围内创建书签(几乎就像语法检查器)。

我不想使用Find() 实用程序,因为我的需求太具体了。


说明

为此,

1/ 检索文档纯文本

我检索文档主要故事的纯文本:

String plainText = ActiveDocument.Range().Text;

2/分析纯文本并得到结果

我将它发送到我的分析器工具,该工具返回带有位置的标记集合: 例如,如果我想检测文档文本中的模式“my pattern”,分析器可以返回标记为{ pattern : "my marker", start: 5, end : 14 },其中“start”和“end" 是发送的纯文本中模式的字符索引。

3/ 在文档中显示结果

我从这些标记创建书签 例如之前的例子,它是:

// init a new range and collapse it 
Word.Range range = activeDocument.Range(); range.Collapse(WdCollapseStart); 

// move character-by-character in the "formatted" text
range.MoveStart(WdUnits.Character, Marker.start ); # Marker.start=5

//set length (end)
range.setRange(range.Start,range.Start+(Marker.End-Marker.Start)); #Marker.end=14

4/ 结果

4.1 全局结果

当文档主要故事包含文本、链接、列表、标题时一切正常: 范围定位良好,纯文本索引与格式化文本索引相关。

4.2 数组问题

当一个文档包含一个数组时,范围被错误地定位了几个字符:纯文本索引与格式化文本索引不完全相关。

我找到了这个问题的原因(在其他论坛中有解释):这是由于非打印字符(7),这是一个以纯文本添加的单元格分隔符。我们可以处理这些字符来计算位置范围,一切正常!

4.3 内容控件、目录、部分和其他问题

当一个文档包含这些元素时,范围也不好定位几个字符。 其他非打印以纯文本显示,但我不明白它的含义以及如何处理计算位置范围。

通过使用“开发者功能区 > 创建模式”显示 Word 元素标记,我们看到每个元素有 2 个标记:将纯文本索引移动 2*元素可以解决问题。好像没问题。

4.4 尾纸问题

我不知道我们如何用英语说“page de garde”(法语),我认为它是“endpaper”:这是具有特定页眉、页脚和内容控件的第一页 :)

当文档包含 Endpaper 时,Range 也会错误地定位几个字符。 但这一次,纯文本中没有非打印标记。

其他信息,当我使用“开发者功能区 > 创建模式”显示 word 元素标记时,我看到了尾纸标记。


问题

  • 如何检测 Word 文档范围内的 Endpaper?
  • 如何理解纯文本索引并不总是与格式化文本索引相关,在包含 的 Word 文档元素的函数中?
  • XML 节点操作会是一个更可靠的替代方案吗?如果是的话,你能给我一个很好的例子来使用 XML Api 管理当前文档中的 bookmars 或其他人吗?

其他资源

我发现了类似的问题:

我希望我的解释很清楚,您可以帮助我了解哪里出了问题或告诉我最好的方法吗?

谢谢,真的。

【问题讨论】:

    标签: vba ms-word vsto


    【解决方案1】:

    它不是很漂亮,但您可以尝试通过正则表达式删除不需要的字符。例如删除\a 字母(代码为7):

    string j = new string(new char[] { (char)7 });
    plainText = Regex.Replace(plainText,string.Format("[{0}]", j), "");
    

    现在您必须识别其他“邪恶”字符并将它们添加到 char 数组中。如果它有效,您将获得一个长度与文档中Characters 的数量相对应的字符串。可能您必须通过试验来调整此代码。 (我不确定您使用的是哪种语言 - 我猜是 C#。)

    更新 另一个想法(如果它适用于您的分析工具):

    将您的问题分解为单个段落:

    foreach(Word.Paragraph pg in activeDocument.Paragraphs)
    {
        Word.Range range = pg.Range();
        string text = range.Text;
        // your stuff here
    }
    

    使用此段落范围对象和包含的文本字符串,您可以执行与尝试处理整个文档对象及其文本相同的操作 - 只是逐段。所有这些段落都可以通过范围和移动操作“寻址”,就像您已经完成的那样。我认为有问题的字符位于段落之外或末尾,因此它们不会影响这些段落内的字符计数。

    由于我无法复制您所说的 endpaper,我无法对其进行验证。此外,我不知道段落是否涵盖了作为页眉和目录的特殊文本范围。但至少你可以将你的问题减少到更小的范围。我觉得值得一试。

    【讨论】:

    • 感谢您的回复。但是我尝试使用此解决方案解决问题,但没有成功。 range.Text.Replace("\a", "").Replace("\u000B", "").Replace("\u000C", "");
    • 奇怪...我以这种方式摆脱了\as。 .Replace("\a", "") 至少不能解决餐桌问题吗? (可能是您的 \a 替换中有一个空格?)
    • 表格是。我已经在使用这个 hack 来解决表格单元格的问题。但是如果我添加一个尾纸(带有内容控制的第一页),每个单元格都会移动一个字符(我认为删除了 \a 字符),但仅限于第一页。很奇怪:(