问题
I need to in a delimited string, replace substring between the delimiters only if the substring matches the replacement value
Using this in Google sheets
The matching
var ifind = ["AA", "CaaL"];
var ireplace = ["zz", "Bob"];
zz replaces AA
Bob replaces CaaL
I have
| Id | Segment |
|----|--------------------|
| 1 | AAA AA|AA|CaaL AA |
| 2 | AAA-AA|AA|CaaL |
| 3 | AAA, AA|AA|AA |
| 4 | AA |
| 5 | AA AA |
| 6 | AA, AA |
| 7 | |
| 8 | CaaL |
| 9 | AA |
I need
| Id | Segment |
|----|-------------------|
| 1 | AAA AA|zz|CaaL AA |
| 2 | AAA-AA|zz|Bob |
| 3 | AAA, AA|zz|zz |
| 4 | zz |
| 5 | AA AA |
| 6 | AA, AA |
| 7 | |
| 8 | Bob |
| 9 | zz |
I have tried (amongst other things)
return [iFinds.reduce((str, k) => str.replace(new RegExp('\\b'+k+'\\b','g'),map[k]), input[0])];
and
return [iFinds.reduce((str, k) => str.replace(new RegExp('(?![ .,]|^)?(\\b' + k + '\\b)(?=[., ]|$)','g'),map[k]), input[0])];
and
return [iFinds.reduce((str, k) => str.split(k).join (map[k]), input[0])];
My function (from here)
function findReplace_mod1() {
const ss = SpreadsheetApp.getActiveSheet();
const col = ss.getRange(2, 3, ss.getLastRow()).getValues();
var ifind = ["AA", "Caal"];
var ireplace = ["zz", "Bob"];
var map = {};
ifind.forEach(function(item, i) {
map[item] = ireplace[i];
});
//const map = { Fellow: 'AAA', bob: 'BBB' };
const iFinds = Object.keys(map);
ss.getRange(2, 3, ss.getLastRow()).setValues(col.map(fr));
function fr(input) {
return [iFinds.reduce((str, k) => str.replace(k, map[k]), input[0])];
}
}
Thanks
回答1:
Your fixed function can look like
function findReplace_mod1() {
const ss = SpreadsheetApp.getActiveSheet();
const col = ss.getRange(2, 3, ss.getLastRow()).getValues();
var ifind = ["AA", "CaaL"];
var ireplace = ["zz", "Bob"];
var map = {};
ifind.forEach(function(item, i) {
map[item] = ireplace[i];
});
//const map = { Fellow: 'AAA', bob: 'BBB' };
const regex = new RegExp("(?<![^|])(?:" + ifind.join("|") + ")(?![^|])", "g");
ss.getRange(2, 3, ss.getLastRow()).setValues(col.map(fr));
function fr(input) {
return input.map(c => c.replace(regex, (x) => map[x]));
}
}
The pattern will look like
/(?<![^|])(?:AA|CaaL)(?![^|])/g
where
(?<![^|])- is a negative lookbehind that fails the match if there is a|or start of a string immediately to the left of the current location(?:AA|CaaL)- aAAorCaaL(?![^|])- is a negative lookahead that fails the match if there is a|or end of a string immediately to the right of the current location.
See the regex demo online (negative lookarounds are replaced with positive ones since the demo is run against a single multiline string, not a set of separate strings).
回答2:
The string to replace
- starts with
|or start of the string^ - ends with
|or end of the string$
The regex needs to be
str.replace(new Regexp(`(\\||^)${k}(\\||$)`), `$1${map[k]}$2`)
/*<ignore>*/console.config({maximize:true,timeStamps:false,autoScroll:false});/*</ignore>*/
function findReplace_mod2() {
const col = [['AAA AA|AA|CaaL AA'], ['AA'], ['AAA-AA|AA|CaaL']];
const map = { AA: 'zz', CaaL: 'Bob' };
const iFinds = Object.keys(map);
console.info(col.map(fr));
function fr(input) {
return [iFinds.reduce((str, k) => str.replace(new RegExp(`(\\||^)${k}(\\||$)`), `$1${map[k]}$2`), input[0])];
}
}
findReplace_mod2();
<!-- https://meta.stackoverflow.com/a/375985/ --> <script src="https://gh-canon.github.io/stack-snippet-console/console.min.js"></script>
来源:https://stackoverflow.com/questions/65063302/in-delimited-string-replace-substring-between-the-delimiters-only-if-the-substri