Я предполагаю, что «aaaaaaaaaa» будет закодирован как «10xa», что означает, что «множитель» n в произведенном паттерне nxc может состоять из более чем одной цифры.
Одна из идей состоит в том, чтобы ввести специальный escape-символ, такой как, например, хеш "#". Всякий раз, когда вход имеет последовательность цифр, пусть алгоритм кодирования добавляет хеш после такой последовательности. Таким образом, его нельзя спутать с шаблоном nxc . В декодировании вы удалили бы такой конечный хеш.
Всякий раз, когда у входа есть хеш, затем экранируйте его так же, как указано выше: добавьте дополнительный хеш сразу после него.
Итак, в вашем примере, 5xfxxx
будет закодировано как 5#xf3xx
. Однако, если последовательность цифр может быть записана в нотации nxc , то хеш не будет использоваться. Поэтому 999x1
будет закодировано как 3x91
, а 122x1
будет закодировано как 122#x1
.
Точно так же, ###
будет закодирован как 3x#
, без экранирования любого хэша. Поэтому применение шаблона nxc всегда будет иметь приоритет над экранированием.
Вот небольшая реализация JavaScript этих функций кодирования / декодирования, в значительной степени опирающаяся на замены на основе регулярных выражений . Вы можете играть с ним:
function encode(s) {
// If a character occurs 3 or more times in sequence, encode that sequence;
// Otherwise, append a hash after any sequence of digits,
// and after each individual hash:
return s.replace(/(.)\1\1+|\d+|#/g, (m, ch) =>
ch ? m.length + "x" + ch : m + "#");
}
function decode(s) {
// If a nxc sequence is found, decode it
// Otherwise, if a character is followed by a hash, remove the hash
return s.replace(/(\d+)x(.)|(.)#/g, (m, times, ch, esc) =>
times ? ch.repeat(+times) : esc);
}
// I/O management of this snippet:
let elemInput = document.querySelector("#input");
let elemEncoded = document.querySelector("#encoded");
let elemDecoded = document.querySelector("#decoded");
let elemCheck = document.querySelector("#check");
elemInput.addEventListener("input", function () { // Whenever input changes:
let encoded = encode(this.value); // Encode...
let decoded = decode(encoded); // ...and decode the encoded string again
elemEncoded.textContent = encoded;
elemDecoded.textContent = decoded;
// Check whether the decoded string is equal to the input:
elemCheck.textContent = this.value == decoded ? "OK" : "Difference!";
});
Input: <input id="input">
<div>Encoded: <span id="encoded"></span></div>
<div>Decoded: <span id="decoded"></span></div>
<div>Check: <span id="check"></span></div>
Очевидно, это означает, что некоторые входы будут иметь закодированный эквивалент, который длиннее исходного ввода. Если вы не используете алгоритм, который всегда кодирует строку, которая равна длине ввода, или если выход не может содержать что-то, что никогда не может появиться на входе, невозможно предотвратить случаи, когда выходной файл длиннее входного. .
Примечание: я удалил флаг s
из регулярных выражений, так как не все браузеры его поддерживают, но он должен быть там, если в вашем вводе могут появляться новые строки.