回答
对于任何想知道我最终是如何做到这一点的人,这里是如何做到的:
首先,我确保传入的每个字符串都将用前导 0 填充,直到它可以除以 8。(保存用于填充的 0 的数量,因为在解压缩时需要它们)
我使用 Corstian 的答案和函数将我的字符串(解释为二进制)压缩为十六进制字符串。虽然我不得不稍作改动。
并非每个长度为 8 的二进制子字符串都会返回正好 2 个十六进制字符。所以对于那些情况,我最终只是在子字符串前面添加了一个 0 。十六进制子字符串将具有相同的值但现在它的长度将是 2。
接下来我使用了 Arnaulds answer 的一个功能。取每个双字符并将其替换为单个字符(十六进制字母表中未使用该字符以避免冲突)。我对每个十六进制字符都做了两次。
例如:
十六进制字符串 11 将变为 h 和 hh 将变为 H
01101111 将变为 0h0H
由于大多数网格的死细胞比活细胞多,我确保 0 能够进一步压缩,再次使用 Arnaulds 方法,但更进一步。
00 -> g | gg -> G | GG -> w | ww -> W | WW -> x | xx -> X | XX-> y | yy -> Y | YY -> z | zz -> Z
这导致Z 代表 4096(二进制)0
压缩的最后一步是在压缩字符串前面添加前导 0 的数量,因此我们可以在解压缩结束时将其去掉。
这就是返回的字符串最终的样子。
amount of leading 0s-compressed string 所以一个 64*64 empty 网格,将导致0-Z
解压缩实际上是反其道而行之。
首先从压缩字符串中拆分代表我们使用多少个前导 0 作为填充的数字。
然后使用 Arnaulds 功能,将进一步“压缩”的字符转换回十六进制代码。
获取这个十六进制字符串并将其转换回二进制代码。正如 Corstian 指出的那样,确保每个二进制子字符串的长度为 8。(如果不使用前导 0 填充子字符串,直到 do,确切地说,长度为 8)
最后一步是去除我们用作填充的前导 0,以使开始字符串可除以 8。
功能
我用来压缩的函数:
/**
* Compresses the a binary string into a compressed string.
* Returns the compressed string.
*/
Codes.compress = function(bin) {
bin = bin.toString(); // To make sure the binary is a string;
var returnValue = ''; // Empty string to add our data to later on.
// If the lenght of the binary string is not devidable by 8 the compression
// won't work correctly. So we add leading 0s to the string and store the amount
// of leading 0s in a variable.
// Determining the amount of 'padding' needed.
var padding = ((Math.ceil(bin.length/8))*8)-bin.length;
// Adding the leading 0s to the binary string.
for (var i = 0; i < padding; i++) {
bin = '0'+bin;
}
for (var i = 0; i < parseInt(bin.length / 8); i++) {
// Determining the substring.
var substring = bin.substr(i*8, 8)
// Determining the hexValue of this binary substring.
var hexValue = parseInt(substring, 2).toString(16);
// Not all binary values produce two hex numbers. For example:
// '00000011' gives just a '3' while what we wand would be '03'. So we add a 0 in front.
if(hexValue.length == 1) hexValue = '0'+hexValue;
// Adding this hexValue to the end string which we will return.
returnValue += hexValue;
}
// Compressing the hex string even further.
// If there's any double hex chars in the string it will take those and compress those into 1 char.
// Then if we have multiple of those chars these are compressed into 1 char again.
// For example: the hex string "ff will result in a "v" and "ffff" will result in a "V".
// Also: "11" will result in a "h" and "1111" will result in a "H"
// For the 0s this process is repeated a few times.
// (string with 4096 0s) (this would represent a 64*64 EMPTY grid)
// will result in a "Z".
var returnValue = returnValue.replace(/00/g, 'g')
.replace(/gg/g, 'G')
// Since 0s are probably more likely to exist in our binary and hex, we go a step further compressing them like this:
.replace(/GG/g, 'w')
.replace(/ww/g, 'W')
.replace(/WW/g, 'x')
.replace(/xx/g, 'X')
.replace(/XX/g, 'y')
.replace(/yy/g, 'Y')
.replace(/YY/g, 'z')
.replace(/zz/g, 'Z')
//Rest of the chars...
.replace(/11/g, 'h')
.replace(/hh/g, 'H')
.replace(/22/g, 'i')
.replace(/ii/g, 'I')
.replace(/33/g, 'j')
.replace(/jj/g, 'J')
.replace(/44/g, 'k')
.replace(/kk/g, 'K')
.replace(/55/g, 'l')
.replace(/ll/g, 'L')
.replace(/66/g, 'm')
.replace(/mm/g, 'M')
.replace(/77/g, 'n')
.replace(/nn/g, 'N')
.replace(/88/g, 'o')
.replace(/oo/g, 'O')
.replace(/99/g, 'p')
.replace(/pp/g, 'P')
.replace(/aa/g, 'q')
.replace(/qq/g, 'Q')
.replace(/bb/g, 'r')
.replace(/rr/g, 'R')
.replace(/cc/g, 's')
.replace(/ss/g, 'S')
.replace(/dd/g, 't')
.replace(/tt/g, 'T')
.replace(/ee/g, 'u')
.replace(/uu/g, 'U')
.replace(/ff/g, 'v')
.replace(/vv/g, 'V');
// Adding the number of leading 0s that need to be ignored when decompressing to the string.
returnValue = padding+'-'+returnValue;
// Returning the compressed string.
return returnValue;
}
我用来解压的函数:
/**
* Decompresses the compressed string back into a binary string.
* Returns the decompressed string.
*/
Codes.decompress = function(compressed) {
var returnValue = ''; // Empty string to add our data to later on.
// Splitting the input on '-' to seperate the number of paddin 0s and the actual hex code.
var compressedArr = compressed.split('-');
var paddingAmount = compressedArr[0]; // Setting a variable equal to the amount of leading 0s used while compressing.
compressed = compressedArr[1]; // Setting the compressed variable to the actual hex code.
// Decompressing further compressed characters.
compressed = compressed// Decompressing the further compressed 0s. (even further then the rest of the chars.)
.replace(/Z/g, 'zz')
.replace(/z/g, 'YY')
.replace(/Y/g, 'yy')
.replace(/y/g, 'XX')
.replace(/X/g, 'xx')
.replace(/x/g, 'WW')
.replace(/W/g, 'ww')
.replace(/w/g, 'GG')
.replace(/G/g, 'gg')
.replace(/g/g, '00')
// Rest of chars...
.replace(/H/g, 'hh')
.replace(/h/g, '11')
.replace(/I/g, 'ii')
.replace(/i/g, '22')
.replace(/J/g, 'jj')
.replace(/j/g, '33')
.replace(/K/g, 'kk')
.replace(/k/g, '44')
.replace(/L/g, 'll')
.replace(/l/g, '55')
.replace(/M/g, 'mm')
.replace(/m/g, '66')
.replace(/N/g, 'nn')
.replace(/n/g, '77')
.replace(/O/g, 'oo')
.replace(/o/g, '88')
.replace(/P/g, 'pp')
.replace(/p/g, '99')
.replace(/Q/g, 'qq')
.replace(/q/g, 'aa')
.replace(/R/g, 'rr')
.replace(/r/g, 'bb')
.replace(/S/g, 'ss')
.replace(/s/g, 'cc')
.replace(/T/g, 'tt')
.replace(/t/g, 'dd')
.replace(/U/g, 'uu')
.replace(/u/g, 'ee')
.replace(/V/g, 'vv')
.replace(/v/g, 'ff');
for (var i = 0; i < parseInt(compressed.length / 2); i++) {
// Determining the substring.
var substring = compressed.substr(i*2, 2);
// Determining the binValue of this hex substring.
var binValue = parseInt(substring, 16).toString(2);
// If the length of the binary value is not equal to 8 we add leading 0s (js deletes the leading 0s)
// For instance the binary number 00011110 is equal to the hex number 1e,
// but simply running the code above will return 11110. So we have to add the leading 0s back.
if (binValue.length != 8) {
// Determining how many 0s to add:
var diffrence = 8 - binValue.length;
// Adding the 0s:
for (var j = 0; j < diffrence; j++) {
binValue = '0'+binValue;
}
}
// Adding the binValue to the end string which we will return.
returnValue += binValue
}
var decompressedArr = returnValue.split('');
returnValue = ''; // Emptying the return variable.
// Deleting the not needed leading 0s used as padding.
for (var i = paddingAmount; i < decompressedArr.length; i++) {
returnValue += decompressedArr[i];
}
// Returning the decompressed string.
return returnValue;
}
网址缩短器
我仍然发现用于共享/粘贴的“压缩”字符串有点长。所以我使用了一个简单的 URL 缩短器 (view here) 来使这个过程对用户来说更容易一些。
现在你可能会问,那为什么还要压缩这个字符串呢?
原因如下:
首先,我的项目托管在 github 页面(gh-pages)上。 gh-pages 的信息页面告诉我们,url 不能 超过 2000 个字符。这意味着最大网格大小将是 2000 的平方根 - 基本 url 的长度,它不是那么大。通过使用这种“压缩”,我们能够共享更大的网格。
现在是第二个原因,这是一个挑战。我发现处理此类问题很有趣,也很有帮助,因为你学到了很多东西。
直播
您可以查看我的项目here 的实时版本。和/或找到 github 存储库 here。
谢谢你
我要感谢所有帮助我解决这个问题的人。尤其是 Corstian 和 Arnauld,因为我最终使用他们的答案来实现我的最终功能。
Sooooo.... 谢谢大家!尝尝吧!