Fix: resolved search-replace operator regexp encoding bug (#6162)

* fix: resolved search-replace operator bug with $ character in replacement strings, added test and more examples

* fix: reset regexp after each title
This commit is contained in:
Saq Imtiaz 2021-11-01 14:24:30 +01:00 committed by GitHub
parent 870c7897ad
commit b6ce353a7d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 23 additions and 11 deletions

View File

@ -121,21 +121,23 @@ exports["search-replace"] = function(source,operator,options) {
flagSuffix = (suffixes[0] ? (suffixes[0][0] || "") : ""),
flags = (flagSuffix.indexOf("g") !== -1 ? "g" : "") + (flagSuffix.indexOf("i") !== -1 ? "i" : "") + (flagSuffix.indexOf("m") !== -1 ? "m" : ""),
isRegExp = (suffixes[1] && suffixes[1][0] === "regexp") ? true : false,
searchTerm,
//Escape regexp characters if the operand is not a regular expression
searchTerm = isRegExp ? operator.operand : $tw.utils.escapeRegExp(operator.operand),
//Escape $ character in replacement string if not in regular expression mode
replacement = isRegExp ? operator.operands[1] : (operator.operands[1]||"").replace(/\$/g,"$$$$"),
regExp;
try {
regExp = new RegExp(searchTerm,flags);
} catch(ex) {
return ["RegExp error: " + ex];
}
source(function(tiddler,title) {
if(title && (operator.operands.length > 1)) {
//Escape regexp characters if the operand is not a regular expression
searchTerm = isRegExp ? operator.operand : $tw.utils.escapeRegExp(operator.operand);
try {
regExp = new RegExp(searchTerm,flags);
} catch(ex) {
return ["RegExp error: " + ex];
}
results.push(
title.replace(regExp,operator.operands[1])
title.replace(regExp,replacement)
);
regExp.lastIndex = 0;
} else {
results.push(title);
}

View File

@ -815,6 +815,10 @@ Tests the filtering mechanism.
expect(wiki.filterTiddlers("[[Unlike conventional online services, TiddlyWiki lets you choose where to keep your data\nUnlike conventional online services, TiddlyWiki lets you choose where to keep your data\nUnlike conventional online services, TiddlyWiki lets you choose where to keep your data\nUnlike conventional online services, TiddlyWiki lets you choose where to keep your data]search-replace:g:regexp<myregexp2>,[]]",anchorWidget).join(",")).toBe("conventional online services, TiddlyWiki lets you choose where to keep your data\nUnlike conventional online services, TiddlyWiki lets you choose where to keep your data\nUnlike conventional online services, TiddlyWiki lets you choose where to keep your data\nUnlike conventional online services, TiddlyWiki lets you choose where to keep your data");
expect(wiki.filterTiddlers("[[Unlike conventional online services, TiddlyWiki lets you choose where to keep your data\nUnlike conventional online services, TiddlyWiki lets you choose where to keep your data\nUnlike conventional online services, TiddlyWiki lets you choose where to keep your data\nUnlike conventional online services, TiddlyWiki lets you choose where to keep your data]search-replace:gm:regexp<myregexp2>,[]]",anchorWidget).join(",")).toBe("conventional online services, TiddlyWiki lets you choose where to keep your data\nconventional online services, TiddlyWiki lets you choose where to keep your data\nconventional online services, TiddlyWiki lets you choose where to keep your data\nconventional online services, TiddlyWiki lets you choose where to keep your data");
expect(wiki.filterTiddlers("[[Hello There\nUnlike conventional online services, TiddlyWiki lets you choose where to keep your data\nguaranteeing that in the decades to come you will still be able to use the notes you take today.]search-replace:gm:regexp<myregexp3>,[]]",anchorWidget).join(",")).toBe("\nUnlike conventional online services, TiddlyWiki lets you choose where to keep your data\n");
expect(wiki.filterTiddlers("[[This is equation $$x$$ end.]search-replace[equation $$x$$ end.],[relation $$x$$ finish.]]").join(",")).toBe("This is relation $$x$$ finish.");
expect(wiki.filterTiddlers("[[This is an amazing TiddlyWiki]] [[How old is TiddlyWiki?. TiddlyWiki is great]] [[My TiddlyWiki is so fast.]] +[search-replace:g:regexp[TiddlyWiki],[TW]]").join(",")).toBe("This is an amazing TW,How old is TW?. TW is great,My TW is so fast.");
expect(wiki.filterTiddlers("[[This is an amazing TiddlyWiki]] [[How old is TiddlyWiki?. TiddlyWiki is great]] [[My TiddlyWiki is so fast.]] +[search-replace::regexp[TiddlyWiki],[TW]]").join(",")).toBe("This is an amazing TW,How old is TW?. TiddlyWiki is great,My TW is so fast.");
expect(wiki.filterTiddlers("[[This is an amazing TiddlyWiki]] [[How old is TiddlyWiki?. TiddlyWiki is great]] [[My TiddlyWiki is so fast.]] +[search-replace:g[TiddlyWiki],[TW]]").join(",")).toBe("This is an amazing TW,How old is TW?. TW is great,My TW is so fast.");
});
it("should handle the pad operator", function() {

View File

@ -1,5 +1,5 @@
created: 20201107112846692
modified: 20201118103305351
modified: 20211101125225197
tags: [[Operator Examples]] [[search-replace Operator]]
title: search-replace Operator (Examples)
type: text/vnd.tiddlywiki
@ -25,8 +25,14 @@ You can also use regular expression capture groups in the replacement string:
`\define names() (\w+)\s(\w+)`
<<.operator-example 4 """[[John Smith]search-replace::regexp<names>,[$2,$1]]""" >>
You can reference the portion of the input that matches the regular expression with `$&`:
<<.operator-example 5 """[[John Smith]search-replace::regexp[John .*],[His name is $&]]""">>
<<.operator-example 6 """[[This is an exciting feature]search-replace::regexp[exciting],[amazing and $&]]""">>
To replace everything but a match using a regular expression and the ''multiline'' (m) flag:
`\define myregexp2() ^(?!Unlike).*$`
<<.operator-example 5 """[[HelloThere]get[text]search-replace:gm:regexp<myregexp2>,[]]""">>
<<.operator-example 7 """[[HelloThere]get[text]search-replace:gm:regexp<myregexp2>,[]]""">>
{{How to remove stop words}}