Last active
November 25, 2024 18:45
-
-
Save Itsindigo/43713cdf0c0d8000952389ffe9920932 to your computer and use it in GitHub Desktop.
Text transformer
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
import { expect, test, describe } from "vitest"; | |
import { transformText } from "./transformText"; | |
describe("transformText", () => { | |
test("should handle replacement commands across a word", () => { | |
expect(transformText("Hello World", "rhllllllrw")).toEqual("hello world"); | |
}); | |
test("handle multiple replace", () => { | |
expect(transformText("xxx", "3rY")).toEqual("YYY"); | |
}); | |
test("handle multiple replace operations in single command", () => { | |
expect(transformText("xxxxxx", "3rY3rZ")).toEqual("YYYZZZ"); | |
}); | |
test("move cursor around, with multiple replace operations", () => { | |
expect(transformText("Hello World", "9lrL7h2rL")).toEqual("HeLLo WorLd"); | |
}); | |
test("replace function when 1 is repetition specified verbosely", () => { | |
expect(transformText("ABCDEFG", "2l1rX3h1rX")).toEqual("XBXDEFG"); | |
}); | |
test("does not append new characters when repeating beyond original word length", () => { | |
expect(transformText("AA", "3l5rB")).toEqual("AB"); | |
}); | |
test("a repeat operation must be followed by a replacement character", () => { | |
expect(() => transformText("AA", "r")).toThrow( | |
new Error("Invalid `r` operation, no proceeding character") | |
); | |
}); | |
}); |
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
import { repeat, isNumberChar, getFirstDigitGroup } from "./utils"; | |
/** | |
* Takes an input string, and a command instruction to mutate the input string. | |
* | |
* 1. `h` Move cursor single position to left. | |
* 2. `l` Move cursor single position to right. | |
* 3. `r<replacement char>` replace the char at the current cursor position with a new char. | |
* e.g Given "ABC", rX would mutate the string to "XBC". | |
* | |
* Additionally, commands can be repeated by prefixing any command with an integer. | |
* e.g `2rT` would replace the next 2 characters with the character `T`. | |
* `9l3h` would move the character 9 positions to the right, and then 3 to the left. | |
*/ | |
export function transformText(target: string, command: string): string { | |
const output = target.split(""); | |
let cursor = 0; | |
for (let i = 0; i < command.length; i++) { | |
let digitGroup: string; | |
let nextCommand = command[i]; | |
let repeatOperationNTimes = 1; | |
if (!nextCommand) { | |
throw new Error("Assert command not null (for TS)"); | |
} | |
if (isNumberChar(nextCommand)) { | |
digitGroup = getFirstDigitGroup(command.slice(i)); | |
i += digitGroup.length; | |
repeatOperationNTimes = parseInt(digitGroup, 10); | |
// Set the command operation once number of repetitions is calculated. | |
nextCommand = command[i]; | |
} | |
switch (nextCommand) { | |
case "h": | |
repeat(() => { | |
cursor = Math.max(cursor - 1, 0); | |
}, repeatOperationNTimes); | |
break; | |
case "l": | |
repeat(() => { | |
cursor = Math.min(cursor + 1, target.length - 1); | |
}, repeatOperationNTimes); | |
break; | |
case "r": | |
let charToRepeat = command[i + 1]; | |
if (!charToRepeat) { | |
throw new Error("Invalid `r` operation, no proceeding character"); | |
} | |
repeat(() => { | |
/* Do not repeat character beyond original word length */ | |
if (cursor > target.length - 1) { | |
return; | |
} | |
output[cursor] = charToRepeat; | |
/* Increment cursor to account for digits in the operation command */ | |
if (repeatOperationNTimes > 1 || digitGroup === "1") { | |
cursor += 1; | |
} | |
}, repeatOperationNTimes); | |
i += 1; | |
break; | |
default: | |
throw new Error(`Unrecognised command operation: ${nextCommand}`); | |
} | |
} | |
return output.join(""); | |
} |
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
export function repeat(operation: () => void, timesToPerform: number) { | |
while (timesToPerform > 0) { | |
operation(); | |
timesToPerform -= 1; | |
} | |
}; | |
export function getFirstDigitGroup(str: string): string { | |
let match = str.match(/(\d+)/); | |
if (!match || !match[1]) { | |
throw new Error("No digit group found"); | |
} | |
return match[1]; | |
} | |
export function isNumberChar(s: string) { | |
if (s.length !== 1) { | |
throw new Error( | |
`Error: isNumberChar asserts a single character is a number "${s}" is ${s.length} characters long.` | |
); | |
} | |
const charCode = s.charCodeAt(0); | |
return charCode >= 48 && charCode <= 57; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment