replaceText()RegEx“未跟随”

时间:2015-06-21 19:23:13

标签: google-apps-script

为什么这个简单的RegEx在Google Docs脚本中似乎不受支持?

  

FOO(?!巴)

我假设Google Apps脚本使用与JavaScript相同的RegEx。这不是这样吗?

我正在使用RegEx:

DocumentApp.getActiveDocument().getBody().replaceText('foo(?!bar)', 'hello');

这会产生错误:

  

ScriptError:无效的正则表达式模式foo(?!bar)

3 个答案:

答案 0 :(得分:4)

正如在对这个问题的评论中所讨论的,这是一个记录在案的限制; replaceText()方法不支持反向前瞻或任何其他捕获组。

  

不完全支持JavaScript正则表达式功能的子集,例如捕获组和模式修饰符。 ref

塞尔建议一个解决方案,“应该可以在较低的层次上操纵你的文件(从段落中提取文本等),但它可能很快变得非常麻烦。”

这可能是什么样子。如果你不介意丢失所有格式,这个例子将应用捕获组,RegExp标志(i用于不区分大小写)和反向预测要更改:

  

小兔子 Foo Foo ,穿过 foobar

为:

  小p弗雷德弗雷德,穿过foobar。

代码:

function myFunction() {
  var body = DocumentApp.getActiveDocument().getBody();
  var paragraphs = body.getParagraphs();
  for (var i=0; i<paragraphs.length; i++) {
    var text = paragraphs[i].getText();
    paragraphs[i].replaceText(".*", text.replace(/(f)oo(?!bar)/gi, '$1red') );
  }
}

答案 1 :(得分:3)

您有一个可以与正则表达式匹配的序列,但该正则表达式也会匹配您不希望更改的一个或多个事物。这种情况的一般解决方案是:

  1. 更改文本,使您知道明确未使用的已知字符序列。实际上,这会为您提供用作变量的字符序列,以保存您不想更改的值。就个人而言,我会用:
    body.replaceText('Q','Qz');
    这将使您的文档中没有与/Q[^z]/匹配的序列。这使您能够使用Qa之类的序列来表示您不想更改的某些文本。我使用Q,因为它的英语使用频率较低。你可以使用任何角色。为了提高效率,请选择一个字符,这样可以在您正在影响的文本中产生较少的更改。
  2. 将您不希望最终更改的内容更改为您现在知道未使用的字符序列之一。例如:
    body.replaceText('foobar','Qa');
    对于您不希望最终更改的任何其他项目,请重复此操作。
  3. 更改您真正想要更改的文字。在这个例子中: body.replaceText('foo','hello'.replace(/Q/g,'Qz'));
    请注意,您需要向新替换文本应用用于打开已知未使用序列的第一个替换。
  4. 将您不想更改的所有内容恢复为原始状态:
    body.replaceText('Qa','foobar');
  5. 恢复用于打开未使用的字符序列的文本:
    body.replaceText('Qz','Q');
  6. 所有这些将是:

    var body = DocumentApp.getActiveDocument().getBody();
    body.replaceText('Q','Qz');      //Open up unused character sequences
    body.replaceText('foobar','Qa'); //Save the things you don't want to change.
    
    //In the general case, you need to apply to the new text the same substitution
    //  which you used to open up unused character sequences.  If you don't you
    //  may end up with those sequences being changed in the new text.
    body.replaceText('foo','hello'.replace(/Q/g,'Qz')); //Make the change you desire.
    
    body.replaceText('Qa','foobar'); //Restore the things you saved.
    body.replaceText('Qz','Q');      //Restore the original sequence.
    

    虽然以这种方式解决问题不允许您使用JavaScript RegExp的所有功能(例如捕获组,预见断言和标志),但它应该保留文档中的格式。

    您可以选择不执行上述步骤1和5,方法是选择较长的字符序列来表示您不想匹配的文字(例如kNoWn1UnUsEd)。但是,这种较长的序列必须根据您对文档中已存在的内容的了解来选择。这样做可以节省几个步骤,但您要么必须搜索未使用的字符串,要么接受您使用的字符串有可能已经存在于文档中,这将导致不希望的替换。

答案 2 :(得分:1)

我想出了一种方法,可以在不弄乱样式的情况下获得JS的大部分str.replace()功能,包括Apps Script中的捕获组和智能替换器。诀窍是使用Javascript的STRING函数和Apps Script的regex.exec()text.deleteText()函数。

text.insertText()

参数说明:

  1. function replaceText(body, regex, replacer, attribute){ var content = body.getText(); const text = body.editAsText(); var match = ""; while (true){ content = body.getText(); var oldLength = content.length; match = regex.exec(content); if (match === null){ break; } var start = match.index; var end = regex.lastIndex - 1; text.deleteText(start, end); text.insertText(start, replacer(match, regex)); var newLength = body.getText().length; var replacedLength = oldLength - newLength; var newEnd = end - replacedLength; text.setAttributes(start, newEnd, attribute); regex.lastIndex -= replacedLength; } } :您要操作的文档正文
  2. body:用作搜索模式的普通JS正则表达式对象
  3. regex:用来返回您要替换的字符串的replacer函数,replacer自动接收两个参数:
    replacer:匹配由match
    II。 regex.exec():用作搜索模式的正则表达式对象
  4. regex:一个Apps脚本attribute对象 例如,如果要将粗体样式应用于替换旧字符串的新字符串,则可以创建attribute属性对象:
boldStyle

提示:

  1. 如何在var boldStyle = {}; boldStyle[DocumentApp.Attribute.BOLD] = true; 中使用捕获组?

    您可以通过replaceText()函数访问所有捕获组,replacer是匹配的整个字符串,match[0]是第一个捕获组,match[1]是第二个捕获组,依此类推。

  2. 如何在match[2]中访问匹配项的索引和位置?

    您可以通过replaceText()函数访问匹配的开始索引(match.index和匹配的结束索引(regex.lastIndex)。

有关JS RegExp的更多深入参考,请参阅Javascript.info的excellent tutorial

示例:

这是replacer函数的一个用例示例。这是对Google Docs转换脚本的降价的简单实现:

replaceText()