Created
March 31, 2025 22:12
-
-
Save OpenSrcerer/103eb12fd83201d595a89d5780bfe91b to your computer and use it in GitHub Desktop.
An out of order replacer for strings/text. Works nicely for cases where you cannot guarantee a specific sort.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// You must at least know this information: | |
type IMatch = { | |
startIndex: number; // Position of the replacement start | |
endIndex: number; // Position of the replacement end | |
replacement: string; // What you wish to replace the substring with | |
hash: string; // Hash or unique identifier for replacement case | |
} | |
/** | |
* A function that when given a string and the appropriate replacement information (see above), | |
* replaces all occurrences of the string in the given positions. | |
* | |
* I had to create this when working on an AI text clarity suggester (like grammarly). | |
* In that use case, I had a list of replacements that needed to be accessed in a random order. | |
* This means that we cannot apply a sort order, therefore rendering the reverse algorithm for replacement unusable here. | |
* | |
* With this approach, earlier indices can be modified and then later ones... or whatever order the user chooses. | |
*/ | |
function applyReplacements(text: string, replacements: IMatch[]): string { | |
// Create a copy of the text to modify | |
let modifiedText = text; | |
// We'll track all adjustments made by previous replacements | |
const adjustments = new Map<string, number>(); | |
replacements.forEach(match => { | |
// Get parameters | |
const adj = adjustments.get(match.hash); | |
const startIndex = !adj ? | |
match.startIndex : (match.startIndex + adj); | |
const endIndex = !adj ? | |
match.endIndex : (match.endIndex + adj); | |
const replacementDelta = match.replacement.length - text.substring(startIndex, endIndex + 1).length; | |
// Replace the text for this specific replacement | |
modifiedText = modifiedText.substring(0, startIndex) + | |
match.replacement + | |
modifiedText.substring(endIndex + 1); | |
// Update changes map for future iterations | |
replacements | |
.filter(r => r.hash !== match.hash && match.endIndex <= r.startIndex) | |
.forEach(r => { | |
const adj2 = adjustments.get(r.hash); | |
adjustments.set(r.hash, adj2 ? adj2 + replacementDelta : replacementDelta) | |
}) | |
}) | |
return modifiedText; | |
} | |
// Test case | |
const originalText = "Ths is a smple txt with erors."; | |
const corrections: IMatch[] = [ | |
{ | |
startIndex: 24, | |
endIndex: 28, | |
replacement: "errors", | |
hash: "error1" | |
}, | |
{ | |
startIndex: 0, | |
endIndex: 2, | |
replacement: "This", | |
hash: "error2" | |
}, | |
{ | |
startIndex: 9, | |
endIndex: 13, | |
replacement: "sample", | |
hash: "error3" | |
}, | |
{ | |
startIndex: 15, | |
endIndex: 17, | |
replacement: "text", | |
hash: "error4" | |
} | |
]; | |
// Correct output: "This is a sample text with errors." | |
console.log(applyReplacements(originalText, corrections)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment