解码包含已编码模式的字符串

时间:2019-04-09 09:23:41

标签: string algorithm encoding decoding

考虑以下问题:

string s = "fffffssss" 

编码的字符串将是5xf4xs,但是如果s中有编码的模式怎么办?例如s="5xfxxx",在编码器中我应该怎么做以避免歧义?前提是编码的字符串必须短于原点之一。

3 个答案:

答案 0 :(得分:0)

要对5xfxxx进行编码,您将获得1x51xx1xf3xx,它没有任何歧义(只有一种方法可以解码这样的字符串,您必须考虑三元组)。当字符串中连续有10个以上的相似字符时,事情可能会变得有些棘手,但是仍然不会有任何歧义。

关于编码字符串必须短于原始字符串的约束,没有这样的保证。 x将被编码为1xx,这是原来的三倍。这是最坏的情况:结果比原始结果长3倍。

如果您正在寻找压缩字符串的方法,建议您看一下Huffman's coding,它简单高效(在压缩方面几乎是最佳选择,并且可以线性运行)。不过,您将不得不考虑二进制字符串。

答案 1 :(得分:0)

如果您希望保持相同的编码方案,其中dxc导致 d (一个数字)重复 c (一个字符),那么您可以简单地使用5xy 5 1xx对诸如y之类的输入进行编码。是的,每当在输入中找到一个数字后跟x时,您将额外支付2个字符的价格。

没有(非损耗)编码可确保输出始终比输入短。甚至更强大:没有编码可以保证将始终创建输入长度或更短的输出,除了根本不编码任何东西(这将始终产生等于其输入的输出长度)。所有压缩方案都依赖于输入中的冗余,并且完全不会使用真正的随机数据来压缩任何内容。因此,压缩方案是否好坏取决于能否在预期输入中充分利用冗余。

一种简单的方案来确保您从不支付超过1个字符的罚款,这是使用初始标记来指示字符串是否已编码。例如,假设第一个字符是0(如果未执行编码),则是1(如果已编码)。然后,

encode("1x2x3x4x") = "01x2x3x4x"; // only 1 character longer than input
encode("1x2x3x4x") = "111xx21xx31xx41xx"; // not so good: 8 chars longer

答案 2 :(得分:0)

我将假设“ aaaaaaaaaaaa”将被编码为“ 10xa”,这意味着在生成的 nxc 模式中的“乘数” n 可能包含多个数字。

一个想法是引入一个特殊的转义字符,例如井号“#”。只要输入有一系列数字,就让编码算法在这样的序列后附加一个哈希。这样,它就永远不会与 nxc 模式混淆。在解码中,您将删除此类尾随哈希。

只要输入本身具有哈希,请按照上述相同的方式对其进行转义:在其后追加一个附加的哈希。

因此,在您的示例中,5xfxxx将被编码为5#xf3xx。但是,如果可以用 nxc 表示法写入一系列数字,则将不使用哈希。因此999x1将被编码为3x91,而122x1将被编码为122#x1。 类似地,###将被编码为3x#,而不转义任何哈希。因此,应用 nxc 模式始终比转义具有更高的优先级。

以下是这些编码/解码功能的一些JavaScript实现,其中高度依赖regular expression-based replacements。您可以玩它:

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标志,但是如果输入中可能出现换行符,则应该在该标志处。