body.replaceText() 方法不支持 JavaScript RegExp 的某些部分。众所周知,不支持捕获组以及模式修饰符 (flags)。
您想要替换三字符序列中的第二个字符,其中第一个和第三个字符不是单个明确指定的字符。对于没有前瞻、后瞻断言和/或捕获组的单个正则表达式,这实际上是不可能的。可以匹配两个字符序列[^\$]\$ 并使用负前瞻(?!\$)。但是,由于 Google Apps 脚本不支持捕获组,因此无法仅替换第二个字符 $。
因此,我们需要使用另一种方法,该方法涉及进行多次替换,以将文本转换为只能匹配所需内容的形式。我们还必须执行额外的替换以将文本返回到其原始形式,只留下我们想要的操作。
我们想要匹配一个通用的东西(在这种情况下是单个字符 $),但我们想要不匹配一些与之非常相似的特定情况(@987654338 @ 和 $$) 将与任何用于匹配所需字符串的正则表达式匹配。我们需要做的是将这些更改为不匹配的内容,执行所需的操作,然后将它们更改回原来的样子。
为此,我们需要执行多个替换操作。下面的代码展示了如何做到这一点。
注意 1:您没有明确指定 $$ 是在文本中的任何位置被忽略,还是仅在文档的开头或结尾处被忽略。 $$$ 呢?目前,下面的代码将“忽略”所有连续包含多个$ 的序列。如果您的要求更具体,可以在此处更改,也可以在自己的代码中更改。
注意 2:对于下面的代码,我假设您只想对要匹配的 $ 字符执行 replaceText()。您实际上并没有说明您想要做什么,但代码可用于适应您想要的任何操作。
//Fake an Object called 'body' so that we can use it as if it was defined
// in Google Apps Script by using the statement:
// var body = DocumentApp.getActiveDocument().getBody();
var body = new SomeItem('$Not\\$yes $not $$');
//The following lines were tested as-is in Google Apps Script:
//Open up character sequences which we can be sure are not used in the text.
// These sequences can be temporarily used to represent the strings we do not want
// to match. In this case we make sure that no 'Q' exists which is not followed
// by a `z`. This lets us use any Q[^z] sequence for anything we desire.
body.replaceText('Q','Qz'); //Make sure no 'Q' exists that is not 'Qz'
//These look a bit strange because we have to use '\\' to get a single '\' within
// a string literal.
body.replaceText('\\\\\\$','Qa'); //Use `Qa` to represent `\$`
//Use `QbQb` instead of `Qb` because of an issue with restoring and `$` in replacement
// string at the end of the string. Also allows handling an odd number of $ in a row.
body.replaceText('\\$\\$','QbQb'); //Use `QbQb` to represent `$$`
body.replaceText('Qb\\$','QbQb'); //Handle an odd number of $ in a row. Not specified
// in the question, but probably desired.
//Here we perform whatever operation was desired on all remaining `$`.
// In this example we will replace them with '_MATCH_'.
// However, for the generalized case, we first we have to perform the
// same preliminary substitution which we did to open up character sequences.
var newText = '_MATCH_';
body.replaceText('\\$',newText.replace(/Q/mg,'Qz')); // Change remaining '$'.
//If the replace() is not performed in the above line then any `Qa`, `Qb`, or `Qz`
// in the new text will end up being replaced with '\$', '$' and 'Q' respectively.
//Restore the temporary changes
body.replaceText('Qa','\\$'); //Restore `Qa` to `\$`
body.replaceText('Qb','$'); //Restore `Qb` to `$`
body.replaceText('Qz','Q'); //Restore all `Qz` to `Q`
//End of lines to be used in Google Apps Script
console.log(body.text);
<head>
<script>
//A function which will perform similar to Google Apps Script so that the
// code is closer to what is available there. No provision is made to eliminate
// the capture group feature of RegExp.
function SomeItem(_text){
this.text = _text;
}
SomeItem.prototype.replaceText=function (regExString,replaceText){
var theRegExp = new RegExp(regExString,"gm");
this.text = this.text.replace(theRegExp,replaceText);
//console.log(regExString,replaceText,this.text);
}
</script>
</head>
<body/>
在 JavaScript 中:
[这部分答案是在将问题更改为希望与不支持 JavaScript RegExp 的全部功能的body.replaceText() 一起使用之前提供的。]
您的RegExp 实际上并不只匹配$。当$ 不在字符串的开头时,它匹配两个字符。 JavaScript 没有后向断言,只有 look-ahead((?=y) 要求 y 跟随匹配,(?!y) 要求 y 不能跟随匹配)。因为 JavaScript 没有后视断言,所以不可能只匹配双字符序列的第二个字符。另一方面,通过使用前瞻断言,我们可以防止基于后续字符的匹配,而无需实际匹配三个字符序列。
为了匹配您想要的内容,我们必须排除 $ 在 $ 之前的匹配以及以下字符是 $ 的匹配。这可以通过将$ 添加到不匹配的字符集来完成(除了\;将其更改为[^\\$]),并使用(?!\$) 添加$ 的前瞻排除项.
这导致正则表达式为:
/(^|[^\\$])\$(?!\$)/g
请注意,这也会将您的非捕获组更改为捕获组,以便当在 replace() 中使用 RegExp 时,它可用于恢复 $ 之前的额外字符。
这是一个使用上述正则表达式匹配您提供的测试字符串的函数示例:
var testMatch = '$Not\\$yes $not $$' //Need double \\ because it is in a string literal.
//Note the use of a capture group and $1 in the replace string to retain the character
// prior to the matching '$'.
result = testMatch.replace(/(^|[^\\$])\$(?!\$)/g,'$1_MATCH_');
console.log(result);