我想出了一种方法来获得大部分 JS 的 str.replace() 功能,包括在 Apps 脚本中捕获组和智能替换器,而不会弄乱样式。诀窍是使用 Javascript 的 regex.exec() 函数和 Apps Script 的 text.deleteText() 和 text.insertText() 函数。
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;
}
}
参数说明:
-
body: 你要操作的文档正文
-
regex:普通的JS正则表达式对象,用作搜索模式
-
replacer:replacer 函数用于返回要替换的字符串,replacer 自动接收两个参数:
我。 match:匹配由regex.exec()生成的对象和
二。 regex: 用作搜索模式的正则表达式对象
-
attribute: 一个 Apps 脚本 attribute 对象
例如,如果您想将粗体样式应用于替换旧字符串的新字符串,您可以创建一个boldStyle 属性对象:
var boldStyle = {};
boldStyle[DocumentApp.Attribute.BOLD] = true;
提示:
- 如何在
replaceText() 中使用捕获组?
您可以从replacer 函数访问所有捕获组,match[0] 是匹配的整个字符串,match[1] 是第一个捕获组,match[2] 是第二个,等等。
- 如何访问
replaceText() 中匹配的索引和位置?
您可以通过 replacer 函数访问匹配的开始索引 (match.index) 和匹配的结束索引 (regex.lastIndex)。
有关 JS RegExp 的更深入参考,请参阅来自 Javascript.info 的 excellent tutorial。
示例:
这是replaceText() 函数的示例用例。这是一个降价到谷歌文档转换脚本的简单实现:
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);
}