Run-Length Encoding For Strings

Encode repeated characters into compact count-letter runs and decode them back with strict validation of malformed input.

JavascriptData Integrity

Code

snippet
export function runLengthEncode(input) {
  if (typeof input !== "string") throw new TypeError("input must be a string");
  const characters = [...input];
  let encoded = "";
  for (let index = 0; index < characters.length; ) {
    let run = 1;
    while (index + run < characters.length && characters[index + run] === characters[index]) {
      run += 1;
    }
    encoded += run + characters[index];
    index += run;
  }
  return encoded;
}

export function runLengthDecode(encoded) {
  if (typeof encoded !== "string") throw new TypeError("encoded must be a string");
  const token = /(\d+)([\s\S])/gu;
  let decoded = "";
  let consumed = 0;
  for (const match of encoded.matchAll(token)) {
    if (match.index !== consumed) throw new SyntaxError("invalid run-length token");
    const count = Number(match[1]);
    if (!Number.isSafeInteger(count) || count <= 0) {
      throw new RangeError("run length must be a positive safe integer");
    }
    decoded += match[2].repeat(count);
    consumed = match.index + match[0].length;
  }
  if (consumed !== encoded.length) throw new SyntaxError("invalid run-length token");
  return decoded;
}