mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
Extensions: Add regex engine
Regex is a method that is commonly used to find and replace parts of a string using a single pattern. Add support for using regex in SillyTavern which allows users to dynamically change various aspects of the chatting experience. Users are able to choose where a given regex script should apply (both invasive and non-invasive options!). Invasive options alter chat history while non-invasive alters markdown display for the entire chat. A new variable called {{match}} is added in regex scripts which substitutes in the found match from the original find regex script. There is a lot more that can be added to this extension, but for now, this is enough. Signed-off-by: kingbri <bdashore3@proton.me>
This commit is contained in:
58
public/scripts/extensions/regex/engine.js
Normal file
58
public/scripts/extensions/regex/engine.js
Normal file
@@ -0,0 +1,58 @@
|
||||
import { substituteParams } from "../../../script.js";
|
||||
export {
|
||||
runRegexScript
|
||||
}
|
||||
|
||||
// From: https://github.com/IonicaBizau/regex-parser.js/blob/master/lib/index.js
|
||||
function regexFromString(input) {
|
||||
// Parse input
|
||||
var m = input.match(/(\/?)(.+)\1([a-z]*)/i);
|
||||
|
||||
// Invalid flags
|
||||
if (m[3] && !/^(?!.*?(.).*?\1)[gmixXsuUAJ]+$/.test(m[3])) {
|
||||
return RegExp(input);
|
||||
}
|
||||
|
||||
// Create the regular expression
|
||||
return new RegExp(m[2], m[3]);
|
||||
}
|
||||
|
||||
// Runs the provided regex script on the given string
|
||||
function runRegexScript(regexScript, rawString) {
|
||||
if (!!(regexScript.disabled)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let match;
|
||||
let newString;
|
||||
const findRegex = regexFromString(regexScript.findRegex);
|
||||
while ((match = findRegex.exec(rawString)) !== null) {
|
||||
const fencedMatch = match[0];
|
||||
const capturedMatch = match[1];
|
||||
|
||||
// TODO: Use substrings for replacement. But not necessary at this time.
|
||||
// A substring is from match.index to match.index + match[0].length or fencedMatch.length
|
||||
const subReplaceString = substituteRegexParams(regexScript.replaceString, { regexMatch: capturedMatch ?? fencedMatch });
|
||||
if (!newString) {
|
||||
newString = rawString.replace(fencedMatch, subReplaceString);
|
||||
} else {
|
||||
newString = newString.replace(fencedMatch, subReplaceString);
|
||||
}
|
||||
|
||||
// If the regex isn't global, break out of the loop
|
||||
if (!findRegex.flags.includes('g')) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return newString;
|
||||
}
|
||||
|
||||
// Substitutes parameters
|
||||
function substituteRegexParams(rawString, { regexMatch }) {
|
||||
let finalString = rawString;
|
||||
finalString = finalString.replace("{{match}}", regexMatch);
|
||||
finalString = substituteParams(finalString);
|
||||
|
||||
return finalString;
|
||||
}
|
Reference in New Issue
Block a user