Javascript replaceText()正则表达式;后面不跟“;

Javascript replaceText()正则表达式;后面不跟“;,javascript,google-apps-script,Javascript,Google Apps Script,你知道为什么谷歌文档脚本中不支持这个简单的正则表达式吗 福(?巴) 我假设GoogleApps脚本使用与JavaScript相同的正则表达式。不是吗 我使用的正则表达式如下所示: DocumentApp.getActiveDocument().getBody().replaceText('foo(?!bar)', 'hello'); 这将生成错误: ScriptError:无效的正则表达式模式foo(?!bar) 正如在关于这个问题的评论中所讨论的,这是一个记录在案的限制;replaceTex

你知道为什么谷歌文档脚本中不支持这个简单的正则表达式吗

福(?巴)

我假设GoogleApps脚本使用与JavaScript相同的正则表达式。不是吗

我使用的正则表达式如下所示:

DocumentApp.getActiveDocument().getBody().replaceText('foo(?!bar)', 'hello');
这将生成错误:

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


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

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

Serge建议了一种变通方法,“应该可以在较低的级别上操作文档(从段落中提取文本等),但很快就会变得相当麻烦。”

下面是它的样子。如果您不介意丢失所有格式,此示例将应用捕获组、RegExp标志(
i
表示大小写不敏感)和反向查找头进行更改:

小兔子跑过食物栏

致:

小兔子弗雷德·弗雷德,跑过食物栏

代码:

函数myFunction(){
var body=DocumentApp.getActiveDocument().getBody();
var parages=body.getparages();

对于(var i=0;i您有一个可以与正则表达式匹配的序列,但该正则表达式也将匹配一个或多个您不希望更改的内容。这种情况的通用解决方案是:

  • 更改文本,使您知道绝对不使用的字符序列。实际上,这将为您提供字符序列,您可以将其用作变量来保存不希望更改的值。就个人而言,我会使用:
    body.replaceText('Q','Qz');

    这将使文档中没有与
    /Q[^z]匹配的序列/
    。这使得您能够使用像
    Qa
    这样的序列来表示您不想更改的某些文本。我使用
    Q
    ,因为它在英语中的使用频率较低。您可以使用任何字符。为了提高效率,请选择一个在您影响的文本中导致少量更改的字符
  • 将您不想更改的内容更改为您现在知道未使用的字符序列之一。例如:
    body.replaceText('foobar','Qa');

    对任何您不希望最终更改的其他项目重复此操作
  • 更改确实要更改的文本。在本例中:
    body.replaceText('foo','hello'.replace(/Q/g,'Qz');

    请注意,您需要将用于打开已知未使用序列的第一个替换应用于新的替换文本
  • 将所有不希望更改的内容恢复到原始状态:
    body.replaceText('Qa','foobar');
  • 还原用于打开未使用字符序列的文本:
    body.replaceText('Qz','Q');
  • 总之,这将是:

    var body=DocumentApp.getActiveDocument().getBody();
    body.replaceText('Q','Qz');//打开未使用的字符序列
    replaceText('foobar','Qa');//保存您不想更改的内容。
    //在一般情况下,需要对新文本应用相同的替换
    //你用来打开未使用的字符序列。如果你不
    //在新的文本中,这些序列可能会被更改。
    body.replaceText('foo','hello'.replace(/Q/g,'Qz');//进行所需的更改。
    replaceText('Qa','foobar');//还原保存的内容。
    replaceText('Qz','Q');//恢复原始序列。
    
    虽然以这种方式解决问题不允许您使用JavaScript的所有功能(例如捕获组、前瞻断言和标志),但它应该保留文档中的格式


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

    我找到了一种方法,可以在应用程序脚本中获得JS的大部分str.replace()功能,包括捕获组和智能替换,而不会弄乱样式。诀窍是使用Javascript的
    regex.exec()
    函数和应用程序脚本的
    text.deleteText()
    text.insertText())
    功能。

    论点解释:
  • body
    :要对其进行操作的文档的正文
  • regex
    :用作搜索模式的普通JS正则表达式对象
  • replacer
    :用于返回要替换的字符串的replacer函数,replacer会自动接收两个参数:
    I.
    match
    :匹配由
    regex.exec()生成的对象
    
    二、
    regex
    :用作搜索模式的正则表达式对象
  • 属性
    :应用程序脚本对象 例如,如果要将粗体样式应用于替换旧字符串的新字符串,可以创建
    粗体样式
    属性对象:
  • var boldStyle={};
    boldStyle[DocumentApp.Attribute.BOLD]=true;
    
    提示:
  • 如何使用
    replaceText()
    中的捕获组?

    您可以从
    replacer
    函数访问所有捕获组,
    match[0]
    是匹配的整个字符串,
    match[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;
      }
    }
    
     function markdownToDocs() {
      const body = DocumentApp.getActiveDocument().getBody();
    
      // Use editAsText to obtain a single text element containing
      // all the characters in the document.
      const text = body.editAsText();
    
      // e.g. replace "**string**" with "string" (bolded)
      var boldStyle = {};
      boldStyle[DocumentApp.Attribute.BOLD] = true;
      replaceDeliminaters(body, "\\*\\*", boldStyle, false);
    
      // e.g. replace multiline "```line 1\nline 2\nline 3```" with "line 1\nline 2\nline 3" (with gray background highlight)
      var blockHighlightStyle = {};
      blockHighlightStyle[DocumentApp.Attribute.BACKGROUND_COLOR] = "#EEEEEE";
      replaceDeliminaters(body, "```", blockHighlightStyle, true);
    
      // e.g. replace inline "`console.log("hello world")`" with "console.log("hello world")" (in "Times New Roman" font and italic)
      var inlineStyle = {};
      inlineStyle[DocumentApp.Attribute.FONT_FAMILY] = "Times New Roman";
      inlineStyle[DocumentApp.Attribute.ITALIC] = true;
      replaceDeliminaters(body, "`", inlineStyle, false);
    
      // feel free to change all the styling and markdown deliminaters as you wish.
    }
    
    // replace markdown deliminaters like "**", "`", and "```"
    function replaceDeliminaters(body, deliminator, attributes, multiline){
      var capture;
      if (multiline){
        capture = "([\\s\\S]+?)"; // capture newline characters as well
      } else{
        capture = "(.+?)"; // do not capture newline characters
      }
      const regex = new RegExp(deliminator + capture + deliminator, "g");
      const replacer = function(match, regex){
        return match[1]; // return the first capture group
      }
      replaceText(body, regex, replacer, attributes);
    }