【问题标题】:Using GAS tools how could I differentiate find() results使用 GAS 工具如何区分 find() 结果
【发布时间】:2013-06-20 21:00:59
【问题描述】:

首先,我要为这个不完全与 GAS 相关的问题道歉,尽管在我看来这显然是 Google Apps 脚本上下文中的“编程”问题。

recent post about string replacements in Google Docs 中,我找到了一种非常可靠的方法来使用find() 方法替换字符串并在textElements 中删除/附加字符串。 正如我在这篇文章中提到的,这种方法非常有效,不受特殊字符的干扰,而且(非常)易于实现。

所以我很高兴并花了一些时间来处理各种名称和地址,并且在某些时候我发现了一个使搜索/替换过程崩溃并弄乱我的文档的条目。我花了一些时间来找出起源,但我终于明白了:

一个例子:一个叫 John 的人住在一条叫 John Kennedy street 的街道上,当我寻找John 在寻找(并替换为#marker#)之前John Kennedy street我死了! (说话的方式)因为它将 - 根据序列顺序 - 插入 John (实际上它将用对应于 John 的字段标记替换 John)代替对应于 John 的标记肯尼迪街 ...之后它将再也找不到约翰肯尼迪街(地址字段将类似于 #marker# Kennedy street !!!

所以问题是:

  • 知道我确切知道将使用的所有字段
  • 知道find() 工具始终以相同的方式在文档中以相同方向迭代
  • 知道我有一个地方可以记住任何有用的参数以及字段名及其替换值
  • 考虑到这个过程可以被逻辑地描述(我已经尽力了),并且我可以使用任何 Gas 特定或 javascript 方法...

了解所有这些,我该如何处理这种情况以防止出现此错误?

我一直在想这件事,但我没有找到任何好主意......

你会如何解决这个问题?

我最好的猜测是,我可以尝试使用 Google 文档的树结构来记住文档中每个项目的位置,并将其用作补充条件)但是因为这会非常复杂(可能有很多不同的本文档中的项目:表格,段落,列表...)我宁愿提前在这里问,因为如果有更简单的事情我没有想到,我会讨厌白白工作。

(感谢您阅读这篇长文。)

【问题讨论】:

    标签: google-apps-script


    【解决方案1】:

    你明白我所说的“坏主意”是什么意思。正如我在另一个条目中所写,您必须迭代文档树并获取需要替换的文本元素。 .findText() 方式是一个不错的快捷方式,它可以让您免于树迭代,但您忘记抓住并按住文本元素以供以后恢复。我会先得到所有替换标签的列表:

    function jumpIntoSearchAndCollect(container, path, tagList) {
      for ( var i=0; i<container.getNumChildren(); i++ ) {
        var element = container.getChild(i);
        switch (element.getType) {
          case DocumentApp.ElementType.PARAGRAPH:
        // add all other container elements here, I'm too lazy
          case DocumentApp.ElementType.TABLE:
            jumpIntoSearchAndCollect(element, path.splice(-1,0,i), tagList);
            break;
          case DocumentApp.ElementType.TEXT:
            if (element.getBackgroundColor() == '#ffff44' && /^#.+#$/.test(element.getText()))
              tagList.push({element: element,
                            marker: element.getText().slice(1,element.getText().length-2),
                            path: path.splice(-1,0,i) };
            break;
          default:
        }
      }
      return;
    }
    var body = DocumentApp.getActiveDocument().getBody();
    var tagList = [];
    jumpIntoSearchAndCollect(body, [], tagList);
    

    现在您必须运行 taglist 并替换文本元素:

    for ( var i=0; i<tagList.length; i++) {
      tagList[i].element
                  .setBackgroundColor('#ffffff')
                  .setText(textToTag(tagList[i].marker));
    }
    

    恢复标记很简单:

    for ( var i=0; i<tagList.length; i++) {
      tagList[i].element
                  .setBackgroundColor('#ffff44')
                  .setText('#' + tagList[i].marker + '#');
    }
    

    此时您应该问:“为什么每次替换都存储一个名为 'path' 的属性?”好吧,如果您的脚本退出,您的元素指针就会丢失。每次你重新输入你的脚本时,你都必须找回你的指针:

    for (var i=0; i<tagList.length; i++) {
      tagList[i].element = restoreElementPointer( body, tagList[i].path);
    }   
    
    function restoreElementPointer (element, path) {
      if (path.length == 1) return element.getChild(path[0]);
      else return restoreElementPointer( element.getChild(path[0]), path.slice(1));
    }
    

    希望我没有输入太多错别字;-)

    PS:请注意,当您的脚本不在时,Google Doc 不会合并文本元素,因为它们在替换后不会突出显示。但也有办法解决这个问题......

    【讨论】:

    • 感谢您的快速回答。因为我认为这种方法非常复杂,但我会尝试一下。当我有“最终”代码时,我会更新。
    • 另外,感谢您抽出宝贵时间来做这件事 +Taras。尽我最大的努力完成并理解递归的东西。关于path.splice(-1,0,i),这不是返回一个空数组(因此总是将一个空数组设置为“路径”属性)吗?为什么不说path.concat(i)?我知道我可能在这里错过了一些东西,如果你能帮助一个菜鸟,我将不胜感激。 :-)
    • path.concat([i]) 可能和path.splice(-1,0,i) 一样好。我使用 splice 因为我知道 splice 总是返回一个新的数组的深层副本。
    猜你喜欢
    • 1970-01-01
    • 2018-03-07
    • 1970-01-01
    • 2017-11-21
    • 2016-07-24
    • 1970-01-01
    • 2014-08-14
    • 2015-08-30
    • 2013-03-28
    相关资源
    最近更新 更多