替换文档中的字符串并撤消

时间:2013-06-14 17:24:24

标签: google-apps-script

在我正在处理的mailMerge脚本中,我使用.replaceText()将字段替换为数据库中的相应值。

界面允许在文档中测试以查看结果是否按预期显示,并且我需要使用'UNDO'函数将我的字段放在原始位置,以便我可以将其与其他值一起使用。脚本绑定到侧栏中的文档,请参阅this post for illustration

下面的脚本通过在内存中保留字段名称替换值来做得非常好。 困扰我的唯一细节是我必须为当前测试数据中没有值的字段定义一个特殊的“空”标签,以防止在文档中丢失它们的轨道。 (我使用了编号标识符,例如°vide12°)。

这是完美的工作,但它并不理想,因为测试模式下的文档并不完全代表最终文档,因为我使用了这些°videXX°......

问题是:当没有数据以不太明显的方式显示时,是否有人有更好的想法或其他方法来“本地化”替换数据? (我知道这听起来很奇怪......这就是我解释整个情况的原因: - )

考虑到Google Docs的构建方式,我认为我可以获得完整的元素结构并从该信息重建文档,但我担心这是不可能的,因为最小的元素是一个段落而字段主要只是单词......

以下是我使用的代码的相关部分,我添加了一些注释以使其(希望)明确。

function valuesInDoc(e){ // this function replaces the fields with database values
  var app = UiApp.getActiveApplication(); 
  var listVal = UserProperties.getProperty('listSel').split(',');
  var replacements = [];
  var doc = DocumentApp.getActiveDocument();
  var body = doc.getBody();
  var find = body.findText('#ch');
  if(find == null){var ui = DocumentApp.getUi() ; ui.alert("Aucun champ (#chX#) trouvé dans le document... Veuillez insérer des identifiants aux endroits souhaités");return app};
  var curData =   UserProperties.getProperty('selItem').split('|');
  var Headers = [];
  var OriHeaders = UserProperties.getProperty('Headers').split('|');
  for(n=0;n<OriHeaders.length;++n){
    Headers.push('#'+OriHeaders[n]+'#');
  }
  var fctSpe = 0 ;
  for(var i in Headers){if(Headers[i].indexOf('SS')>-1){fctSpe = i}}
  for(var n=0;n<listVal.length;++n){
    var realIdx = Number(listVal[n]);
    var newField = ChampSpecial(curData,realIdx,fctSpe);
    if(newField!=''){replacements.push(newField+'∏'+'#ch'+(n+1)+'#')};
    //Logger.log('value in '+n+'='+realIdx+'  >>  '+Headers[realIdx]+'  =  '+ChampSpecial(curData,realIdx,fctSpe))
    app.getElementById('textField'+(n+1)).setHTML(ChampSpecial(curData,realIdx,fctSpe));
    if(e.parameter.source!='dataSelection'){
    body.replaceText('#ch'+(n+1)+'#',newField);
    }
  }
  UserProperties.setProperty('replacements',replacements.join('|'));// memorize the replacement pattern
  cloakOn();// hide hidden fields
  return app;
}



function fieldsInDoc(e){ // this function does the reverse process and restores the field identifiers
  cloakOff();// show hidden fields
  var replacements = UserProperties.getProperty('replacements').split('|');
  var doc = DocumentApp.getActiveDocument();
  var body = doc.getBody();
  for(var n=0;n<replacements.length;++n){
    var field = replacements[n].split('∏')[1];
    var testVal = replacements[n].split('∏')[0];    
    body.replaceText(testVal,field);
    }
}

function ChampSpecial(curData,idx,ref){ // this function handles a special case for a specific field, the relevant part is right below, see comment
  if(idx==-1){return''};
  if(curData[idx-1]==''){return'°vide'+idx+'°'};// this is the "empty" identifier
  if(idx<ref){return curData[idx]};
  if(idx>ref){return curData[idx-1]}
  var firstSpace = curData[idx-1].indexOf(' ');
  var apos = curData[idx-1].indexOf("'");
//Logger.log('firstSpace='+firstSpace+'  apos='+apos)
  if(firstSpace<4&&firstSpace>-1){return curData[idx-1].substring(firstSpace+1)};
  if(apos<3&&apos>-1){return curData[idx-1].substring(apos+1)};
  return curData[idx-1];
}

编辑:感谢Mogsdad的精彩回答,我写了这两个函数来隐藏/显示未使用的字段。在我的情况下,我使用°XX°(XX = 2位数字)来跟踪未修改的字段,我必须修改他的代码以查找此特定字符串并使用2个循环来获取所有字段。

我从菜单和其他两个处理替换的函数调用这些函数(我也更新了上面的代码)

这可能看起来浪费时间,因为我迭代了100多次,但结果是瞬间的...所以为什么要这么麻烦? 这是代码,以防它给某人一个想法。

function cloakOn() {
  var doc = DocumentApp.getActiveDocument();
  var body = doc.getBody();
  var found = [];
  for(var n=1;n<23;++n){
    for(var f=0;f<5;++f){
      if(f==0){found[f] = body.findText('°'+Utilities.formatString("%02d",n)+'°')}else{found[f] = body.findText('°'+Utilities.formatString("%02d",n)+'°',found[f-1])}
      if(found[f]!=null){
        var elemTxt = found[f].getElement().asText();
        elemTxt.setFontSize(found[f].getStartOffset(), found[f].getEndOffsetInclusive(),0)
        var background = elemTxt.getBackgroundColor(found[f].getStartOffset()) || "#ffffff";
        elemTxt.setForegroundColor(found[f].getStartOffset(), found[f].getEndOffsetInclusive(), background);
      }
    }
  }
}

function cloakOff() {
  var doc = DocumentApp.getActiveDocument();
  var body = doc.getBody();
  var found = [];
  for(var n=1;n<23;++n){
    for(var f=0;f<5;++f){
      if(f==0){found[f] = body.findText('°'+Utilities.formatString("%02d",n)+'°')}else{found[f] = body.findText('°'+Utilities.formatString("%02d",n)+'°',found[f-1])}
      if(found[f]!=null){
        var elemTxt = found[f].getElement().asText();
        var size = elemTxt.getParent().getFontSize();
        elemTxt.setFontSize(found[f].getStartOffset(), found[f].getEndOffsetInclusive(),size)
        var background = elemTxt.getBackgroundColor(found[f].getStartOffset()) || "#000000";
        elemTxt.setForegroundColor(found[f].getStartOffset(), found[f].getEndOffsetInclusive(), background);
      }
    }
  }
}

1 个答案:

答案 0 :(得分:5)

塞尔,我一直在研究同样的问题!我有一个部分的解决方法可以分享,还有一些想法可以更进一步。

Gill在old forum上雄辩地阐述了无法在Google文档中嵌入隐藏文字的方法。如果有,你的邮件将是微不足道的!

如何使你的标签或“饼干”(几乎)看不见?下面是一个在文档中添加“隐藏”功能的scriplet。它也有额外的东西;它向用户查询要隐藏的文本,然后搜索该文本的所有实例并隐藏它们。我确定的想法是使文本尽可能小(fontsize 0)并将前景色与背景色匹配。

// in menu:       .addItem('Text Cloaking', 'cloakOn')

/**
 * Find all matches of target text in current document, and cloak them.
 * At this time, that consists of making the text tiny, but still visible.
 * This is an experiment - my hope was to find a way to implement something
 * like document variables, placeholders that would not be forgotten, so
 * that values could be changed, or even dynamic.
 *
 * @param {String} target     (Optional) The text or regex to search for. 
 *                            See Body.findText() for details.
 * @param {String} background (Optional) The desired highlight color.
 *                            A default orange is provided.
 */
function cloakOn(target) {
  // If no search parameter was provided, ask for one
  if (arguments.length == 0) {
    var ui = DocumentApp.getUi();
    var result = ui.prompt('Text Cloaking',
      'Enter text to cloak:', ui.ButtonSet.OK_CANCEL);
    // Exit if user hit Cancel.
    if (result.getSelectedButton() !== ui.Button.OK) return;
    // else
    target = result.getResponseText();
  }
  var doc = DocumentApp.getActiveDocument();
  var bodyElement = doc.getBody();
  var searchResult = bodyElement.findText(target);

  while (searchResult !== null) {
    var thisElement = searchResult.getElement();
    var thisElementText = thisElement.asText();

    //Logger.log(url);
    thisElementText.setFontSize(searchResult.getStartOffset(), searchResult.getEndOffsetInclusive(),0);
    var background = thisElementText.getBackgroundColor(searchResult.getStartOffset()) || "#ffffff";
    thisElementText.setForegroundColor(searchResult.getStartOffset(), searchResult.getEndOffsetInclusive(),
                                       background);

    // search for next match
    searchResult = bodyElement.findText(target, searchResult);
  }
}

要在文本替换操作中使用此功能,替换文本将带有隐藏标记(正如您所做的那样)。我想你想让你的标签尽可能短,这样他们在最终文档中占用的空白区域非常小 - 我正在使用一系列unicode字符作为数字,给出大范围的2 -digit'数字',不太可能出现在任何其他背景下。