【问题标题】:vba Word: Why can Word use special chars in bookmark creation, and I cant?vba Word:为什么Word可以在书签创建中使用特殊字符,而我不能?
【发布时间】:2015-04-12 04:50:28
【问题描述】:

这是一个令人头疼的问题: 我正在尝试以编程方式为文档中的现有标题创建隐藏书签,以便我可以在文档中的其他位置创建指向这些书签的超链接。 (我想使用超链接而不是交叉引用,所以我可以为链接指定我自己的“显示文本”,而使用交叉引用是不可能的)。

我希望我的书签以它们相关的标题命名,并带有自定义前缀。 示例:

  1. 样式:标题1
  2. 标题文字:入口和走廊
  3. 书签名称:_Hd1_Entrance_&_Hallway

我指定了一个自定义前缀,以使每个书签的样式独一无二,因此我可以在文档中拥有 2 个匹配的标题,只要它们具有不同的标题样式。 (例如:_Hd1_Entrance_&_Hallway_Hd3_Entrance_&_Hallway

问题是:如果我的标题包含特殊字符,如“&”,我会收到“错误的书签名称”错误,据我所知,这已记录在网络上。我只能使用有限的字符集。

那么,如果我使用 Word 自己的对话框手动创建一个超链接,选择一个“放置在此文档中”,例如“入口和走廊”之类的标题,Word 管理这个没有问题怎么办?创建 Hlink 后,我现在可以在 Word 的“书签”对话框中看到与此 Hlink 关联的隐藏书签 - 并且非常高兴地将其命名为“_Entrance _&_Hallway”。这让我很困惑!

有人解释一下吗?我真的很想能够利用同样的功能,但无法理解如何。任何帮助都非常有价值! 谢谢,

Sub ScratchPad_Bookmarks()
Dim doc As Document
Dim rng As Range
Dim sHdName As String
Dim sBmName As String
    Set doc = ActiveDocument
    'Insert a heading at start of document
    sHdName = "Entrance & Hallway"
    doc.Range.InsertBefore sHdName & vbCr
    doc.Paragraphs(1).Range.Style = doc.Styles("Heading 1")

    'Find the above heading in the active document
    Set rng = doc.Range
    With rng.Find
        .ClearFormatting
        .Text = sHdName
        .Style = "Heading 1"
        If Not .Execute Then
            'Heading not found, so quit
            Exit Sub
        End If
    End With

    'rng has collapsed to the found heading, so create a bookmark
    'rng.Select 'debug
    sBmName = Replace(rng.Text, " ", "_")
    rng.Collapse wdCollapseStart
    rng.Bookmarks.Add sBmName
    'sBmName contains '&' so this throws a Runtime error:
    '5828: Bad Bookmark Name  (as expected)
End Sub

上述方法无效。但是,自己测试手动操作很容易。只需创建一个包含 '&' 字符的标题,并将其样式设置为 Heading 1。 在下一段中,使用 Word 自己的对话框插入超链接。选择 Place In This Doc 并选择您刚刚创建的标题。应该不是问题。 现在打开 Word 的书签对话框,启用 隐藏书签 视图,瞧:一个带有“&”字符的隐藏书签。 (Wd 2010)说什么?!

【问题讨论】:

  • 您确定将& 正确包含在字符串中吗?您能否向我们展示您尝试定义书签的代码行?
  • 对上述内容表示歉意。即使是简单的指令也会引发运行时错误——例如:r.Bookmarks.Add "This & That"。这与预期的一样。我已经确认我的字符串明确包含“&”——这实际上是我想要的。即:我的标题必须使用 & 而不是“and”。
  • 阅读官方documentation,我可以阅读书签名称应该是一个字;我担心这就是原因。
  • 附言。我对VBA for Word的知识很差,你可能想等待别人的回答;但我清楚地阅读了“书签的名称。名称不能超过一个单词。”在文档中。
  • 我相信使用下划线而不是空格可以克服这个问题,这就是 Word 实现多字书签的方式,就像上面的示例一样。不过还是谢谢你。

标签: vba ms-word bookmarks


【解决方案1】:

IMO Word 是在“作弊”,要么违反了自己的书签名称规则,要么拒绝了规范允许的所有名称。

如果您回到 .docx 的早期 ECMA 标准,书签的名称被定义为 ST_String,这是对 xsd:string 的限制,最大长度为 255 个字符。我认为这在任何 ECMA 或 ISO 版本的标准中都没有改变。

但是,Microsoft 的实施说明 [MS-OE376].pdf(属于 ECMA 版本规范)和 [MS-OI29500].pdf(属于 2012 ISO 版本)指定名称可以是 no超过 40 个字符,但不要描述任何其他限制。

我(以前)的理解是书签名称限制为 40 个字符,必须由“字母”、“数字”和“下划线”组成,并且必须以下划线(用于隐藏的书签)或字母开头。 (不确定,例如“_1”)。而且我相信 VBA 仍然强制执行这些规则,尽管我从未检查过它对“字母”或“数字”的理解是什么——是否允许使用非拉丁字母/数字?

但是,如果您将文档另存为 .xml 或在 .docx 中编辑 document.xml,您可以修改书签名称以使其包含,例如“&”。此外,Word 将重新保存此类字符。但是打开时会截断名字到40个字符,重新保存时不会保留原来的名字。我也不认为标准中使用首字母“_”来表示“隐藏”。

因此,根据规范,我会说 Word 是“作弊”,不允许您使用所有可能的名称,而不是“作弊”,允许超链接目标包含“&”。

您可以在 VBA 中的 Windows 版本的 Word 中插入带有“&”的书签,方法是使用 InsertXML 插入带有预配置书签名称的 XML 块(请参阅下面的一些简单示例代码),但我怀疑您将不得不更加努力移动书签。您可能必须提取您想要“覆盖”的内容的现有 XML,然后用 bookmarkStart 和 bookmarkEnd 标签包围它,这对我来说听起来像是一个非常讨厌的练习。

作为最后的观察,AFAICR 可以为旧表单字段指定的书签名称有 20 个字符的长度限制。

那个代码:

Sub insertbm()
Dim x As String
x = ""
x = x & "<?xml version='1.0' encoding='utf-8' standalone='yes'?>"
x = x & "<pkg:package xmlns:pkg='http://schemas.microsoft.com/office/2006/xmlPackage'>"
x = x & "  <pkg:part pkg:name='/_rels/.rels' pkg:contentType='application/vnd.openxmlformats-package.relationships+xml'>"
x = x & "    <pkg:xmlData>"
x = x & "      <Relationships xmlns='http://schemas.openxmlformats.org/package/2006/relationships'>"
x = x & "        <Relationship Id='rId1' Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument' Target='word/document.xml' />"
x = x & "      </Relationships>"
x = x & "    </pkg:xmlData>"
x = x & "  </pkg:part>"
x = x & "  <pkg:part pkg:name='/word/document.xml' pkg:contentType='application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml'>"
x = x & "    <pkg:xmlData>"
x = x & "      <w:document xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>"
x = x & "        <w:body>"
x = x & "          <w:p>"
x = x & "            <w:bookmarkStart w:id='0' w:name='bookmark&amp;name' />"
x = x & "            <w:r>"
x = x & "              <w:t>"
x = x & "bookmarkedtext</w:t>"
x = x & "            </w:r>"
x = x & "            <w:bookmarkEnd w:id='0' />"
x = x & "          </w:p>"
x = x & "        </w:body>"
x = x & "      </w:document>"
x = x & "    </pkg:xmlData>"
x = x & "  </pkg:part>"
x = x & "</pkg:package>"
Selection.InsertXML x
End Sub

【讨论】:

  • 非常感谢比巴迪亚。对我来说,这就像一罐蠕虫,但我把这件事放在了脑海里。
猜你喜欢
  • 2019-11-02
  • 2013-08-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-07
  • 1970-01-01
  • 2011-11-17
相关资源
最近更新 更多