【问题标题】:Replace text with hyperlink using Google apps script使用 Google 应用脚本将文本替换为超链接
【发布时间】:2020-10-01 13:39:11
【问题描述】:

我需要在不影响超链接的情况下替换单词(必须为替换的单词保留超链接),并且那些没有超链接的替换必须以常规方式进行。

Here is the link of the coded Docs

我试过了

function run() {
    var findtext = "Search";
    var replacetext = "Replacer";

    var body = DocumentApp.getActiveDocument().getBody();
    var foundElement = body.findText(findtext);

    while (foundElement != null) {
        var foundText = foundElement.getElement().asText();
        var startOffset = foundElement.getStartOffset();
        var endOffsetInclusive = foundElement.getEndOffsetInclusive();
        var hyperlink = foundText.getLinkUrl(0);
        foundText.insertText(0, findtext);
        foundText.setLinkUrl(startOffset + findtext.length, endOffsetInclusive + findtext.length, hyperlink);
        foundText.deleteText(startOffset + findtext.length, endOffsetInclusive + findtext.length)

        foundElement = body.findText(findtext, foundElement);
    }
}
  

【问题讨论】:

    标签: google-apps-script google-docs-api


    【解决方案1】:

    主要问题是将findText 的结果视为一个单词。

    这很棘手,因为您无法获得“单词”元素。你必须:

    • 获取findText 返回的整个段落元素。这包含搜索结果。
    • 获取找到的单词的开头和结尾的索引值。
    • 获取该索引处的超链接
    • 删除这些索引之间的文本
    • 插入新文本,然后为超链接分配新索引。

    例如:

    foundText.insertText(0, findtext)
    

    在结果所在元素的开始处插入您要查找的文本,即“搜索”。

    这个:

    var hyperlink = foundText.getLinkUrl(0)
    

    这只会获取在段落开头找到的超链接,例如,这意味着如果段落的第一个单词有超链接,这就是它将返回的内容。在getLinkUrl() 中应该使用搜索结果的起始索引。

    解决方案

    此代码将替换文本并保留超链接(如果有)。

    function replaceTextKeepHyperlink(textToReplace, ReplacementText) {
      var body = DocumentApp.getActiveDocument().getBody();
      var searchResult = body.findText(textToReplace);
      
      while (searchResult != null) {
        
        // Getting info about result
        var foundText = searchResult.getElement().asText();
        var start = searchResult.getStartOffset();
        var end = searchResult.getEndOffsetInclusive();
        var hyperlink = searchResult.getElement().getLinkUrl(start);
        
        // Modifying text
        foundText.deleteText(start, end)
        foundText.insertText(start, ReplacementText)
        foundText.setLinkUrl(start, start + ReplacementText.length - 1, hyperlink)
        
        // Moving to next search result
        searchResult = body.findText(textToReplace, searchResult);
      }
    }
    

    但它不会保留任何其他格式,因此您需要在代码的“获取信息”和“修改”部分添加一些行。

    参考


    更新

    mshcruz 发现如果你用这样的参数调用函数:

    replaceTextKeepHyperlink("Search", "PrefixedSearch")
    

    该函数陷入无限循环,因为它在刚刚替换的文本中找到它正在寻找的文本,替换该部分,等等。

    他提供了包含在下面的尝试块的修复,以避免在文档末尾找到 textToReplace 时产生的错误:

    function replaceTextKeepHyperlink(textToReplace, ReplacementText) {
      var body = DocumentApp.getActiveDocument().getBody();
      var searchResult = body.findText(textToReplace);
      
      while (searchResult != null) {
        var foundText = searchResult.getElement().asText();
        var start = searchResult.getStartOffset();
        var end = searchResult.getEndOffsetInclusive();
        var hyperlink = searchResult.getElement().getLinkUrl(start);
        
        foundText.deleteText(start, end)
        foundText.insertText(start, ReplacementText)
        foundText.setLinkUrl(start, start + ReplacementText.length - 1, hyperlink)
        
        try {
          let rangeBuilder = DocumentApp.getActiveDocument().newRange();
          rangeBuilder.addElement(searchResult.getElement(), start, end+ReplacementText.length - 1);
          searchResult = rangeBuilder.getRangeElements()[0];
        } catch (e){
          Logger.log("End of Document")
          return null
        }
        
        searchResult = body.findText(textToReplace, searchResult);
      }
    }
    

    【讨论】:

    • 如果ReplacementText包含textToReplace,但前缀比textToReplace.length长,比如“MyText”和“MyLongText”,这个函数似乎会陷入无限循环。显然原因是textToReplace 向前移动,body.findText(textToReplace, searchResult) 返回相同的textToReplace,而不是下一个。
    • @mshcruz 感谢您提出这个问题!你的意思是ReplacementText 是“MyLongText”而textToReplace 是“MyText”还是相反?我刚刚尝试使用replaceTextKeepHyperlink("Search", "SearchFix")replaceTextKeepHyperlink("Search", "Sear"),它对我有用。能否提供一个失败的测试用例,我看看,谢谢!
    • 类似replaceTextKeepHyperlink('Text', 'MyLongText'),或者,使用你的例子,replaceTextKeepHyperlink('Search', 'PrefixedSearch')
    • 如果我们在插入文本后更新searchResult RangeElement,似乎问题就解决了,比如:let rangeBuilder = DocumentApp.getActiveDocument().newRange(); rangeBuilder.addElement(searchResult.getElement(), start, end+ReplacementText.length - 1); searchResult = rangeBuilder.getRangeElements()[0];
    • 不错的@mshcruz!我已经在包含它的答案中添加了一个编辑。
    猜你喜欢
    • 2012-01-14
    • 2018-03-22
    • 2017-10-15
    • 1970-01-01
    • 2023-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多