考虑以下问题:
string s = "fffffssss"
编码的字符串将是5xf4xs
,但是如果s
中有编码的模式怎么办?例如s="5xfxxx"
,在编码器中我应该怎么做以避免歧义?前提是编码的字符串必须短于原点之一。
答案 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
标志,但是如果输入中可能出现换行符,则应该在该标志处。