为什么这个简单的RegEx在Google Docs脚本中似乎不受支持?
FOO(?!巴)
我假设Google Apps脚本使用与JavaScript相同的RegEx。这不是这样吗?
我正在使用RegEx:
DocumentApp.getActiveDocument().getBody().replaceText('foo(?!bar)', 'hello');
这会产生错误:
ScriptError:无效的正则表达式模式foo(?!bar)
答案 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)
您有一个可以与正则表达式匹配的序列,但该正则表达式也会匹配您不希望更改的一个或多个事物。这种情况的一般解决方案是:
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'); //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()
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
:用作搜索模式的普通JS正则表达式对象regex
:用来返回您要替换的字符串的replacer函数,replacer自动接收两个参数:
replacer
:匹配由match
和
regex.exec()
:用作搜索模式的正则表达式对象regex
:一个Apps脚本attribute对象
例如,如果要将粗体样式应用于替换旧字符串的新字符串,则可以创建attribute
属性对象:boldStyle
var boldStyle = {};
boldStyle[DocumentApp.Attribute.BOLD] = true;
中使用捕获组?replaceText()
函数访问所有捕获组,replacer
是匹配的整个字符串,match[0]
是第一个捕获组,match[1]
是第二个捕获组,依此类推。match[2]
中访问匹配项的索引和位置? replaceText()
函数访问匹配的开始索引(match.index
和匹配的结束索引(regex.lastIndex
)。有关JS RegExp的更多深入参考,请参阅Javascript.info的excellent tutorial。
这是replacer
函数的一个用例示例。这是对Google Docs转换脚本的降价的简单实现:
replaceText()