Regex: Add overlay replacement strategy

As opposed to making the match variable include the entire regex
match, overlay the replacement string over the regex match and splice
out whatever's already in the replacement string from the regex match.

This new strategy helps save time when editing messages since match
prefix and suffix phrases have a lower chance of being repeated on
every edit. The overlay strategy also preserves uniqueness if the user
decides to change something in the edited text.

However, overlay can cause issues especially with punctiation,
so the strategy isn't chosen by default when creating a new regex.

Signed-off-by: kingbri <bdashore3@proton.me>
This commit is contained in:
kingbri
2023-07-06 00:36:48 -04:00
parent 3168ee536e
commit fb69397ac1
3 changed files with 67 additions and 4 deletions

View File

@@ -103,6 +103,13 @@
<span data-i18n="Substitute Regex">Substitute Regex</span>
</label>
</div>
<div class="flex-container flexFlowColumn alignitemsstart">
<small>Replacement Strategy</small>
<select name="replace_strategy_select" class="margin0">
<option value="0">Replace</option>
<option value="1">Overlay</option>
</select>
</div>
</div>
</div>
</div>

View File

@@ -14,6 +14,11 @@ const regex_placement = {
SENDAS: 4
}
const regex_replace_strategy = {
REPLACE: 0,
OVERLAY: 1
}
// Originally from: https://github.com/IonicaBizau/regex-parser.js/blob/master/lib/index.js
function regexFromString(input) {
try {
@@ -32,6 +37,7 @@ function regexFromString(input) {
}
}
// Parent function to fetch a regexed version of a raw string
function getRegexedString(rawString, placement, { characterOverride } = {}) {
if (extension_settings.disabledExtensions.includes("regex") || !rawString || placement === undefined) {
return;
@@ -78,7 +84,14 @@ function runRegexScript(regexScript, rawString, { characterOverride } = {}) {
// 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, trimCapturedMatch ?? trimFencedMatch, { characterOverride });
const subReplaceString = substituteRegexParams(
regexScript.replaceString,
trimCapturedMatch ?? trimFencedMatch,
{
characterOverride,
replaceStrategy: regexScript.replaceStrategy ?? regex_replace_strategy.REPLACE
}
);
if (!newString) {
newString = rawString.replace(fencedMatch, subReplaceString);
} else {
@@ -106,10 +119,45 @@ function filterString(rawString, trimStrings, { characterOverride } = {}) {
}
// Substitutes regex-specific and normal parameters
function substituteRegexParams(rawString, regexMatch, { characterOverride } = {}) {
function substituteRegexParams(rawString, regexMatch, { characterOverride, replaceStrategy } = {}) {
let finalString = rawString;
finalString = finalString.replace("{{match}}", regexMatch);
finalString = substituteParams(finalString, undefined, characterOverride);
let overlaidMatch = regexMatch;
if (replaceStrategy === regex_replace_strategy.OVERLAY) {
const splitReplace = finalString.split("{{match}}");
// There's a prefix
if (splitReplace[0]) {
const splicedPrefix = spliceSymbols(splitReplace[0], false);
overlaidMatch = overlaidMatch.replace(splicedPrefix, "").trim();
}
// There's a suffix
if (splitReplace[1]) {
const splicedSuffix = spliceSymbols(splitReplace[1], true);
overlaidMatch = overlaidMatch.replace(new RegExp(`${splicedSuffix}$`), "").trim();
}
}
// Only one match is replaced. This is by design
finalString = finalString.replace("{{match}}", overlaidMatch) || finalString.replace("{{match}}", regexMatch);
return finalString;
}
// Splices symbols and whitespace from the beginning and end of a string
// Using a for loop due to sequential ordering
function spliceSymbols(rawString, isSuffix) {
let offset = 0;
for (const ch of isSuffix ? rawString.split('').reverse() : rawString) {
if (ch.match(/[^\w.,?'!]/)) {
offset++;
} else {
break;
}
}
return isSuffix ? rawString.substring(0, rawString.length - offset) : rawString.substring(offset);;
}

View File

@@ -119,6 +119,9 @@ async function onRegexEditorOpenClick(existingId) {
editorHtml
.find(`input[name="substitute_regex"]`)
.prop("checked", existingScript.substituteRegex ?? false);
editorHtml
.find(`select[name="replace_strategy_select"]`)
.val(existingScript.replaceStrategy ?? 0);
existingScript.placement.forEach((element) => {
editorHtml
@@ -161,7 +164,12 @@ async function onRegexEditorOpenClick(existingId) {
substituteRegex:
editorHtml
.find(`input[name="substitute_regex"]`)
.prop("checked")
.prop("checked"),
replaceStrategy:
parseInt(editorHtml
.find(`select[name="replace_strategy_select"]`)
.find(`:selected`)
.val()) ?? 0
};
saveRegexScript(newRegexScript, existingScriptIndex);