编码 - 避免重复字符

时间:2018-03-07 15:13:18

标签: javascript jquery string math encoding

我想使用4个不同的位(A,B,C,D)将整数编码为字符串:

因此我在这里写了一个简单的 Int to customBase conversion

function messageToCustomBase(message, charset) {
   var base = charset.length,
      integer = message,
      result = ""
   do {
        var index = integer % base
    result = charset[index] + result
    integer = parseInt(integer/base)
    } while (integer > 0)
  return result   
}

代码工作正常,编码看起来像这样

0 --> "A"
1 --> "B"
2 --> "C"
...
100 --> "BCBA"
...
10000 --> "CBDABAA"

由于特殊程序,我实际上强制使用特殊编码算法将整数转换为字符串...

1. should have as small a length as possible

2. uses maximum four different letters (4 different bits -> A, B, C, D)

3. Prevents never having the same letters next to each other

   "ABADADA" -> legit
   "ABCDAD" -> legit
   "BABCA" -> legit
   "CDDABC" -> not legit (because of "D" "D")
   "BBBACAB" -> not legit (because of "B" "B" "B")

问题:>如何通过编辑messageToBase函数来避免多个字符相互跟随?

示例:编码整数42 会给出结果“CCC”。 因为在我的特殊情况下,“CCC”无效,它应该编码不同(可能是例如“CBCDCA”,......)

注意:字符串必须能够在以后解码,因此只需在解码后在重复字符之间添加随机填充字符就不是一个有效的解决方案。

注意Here you can find a working fiddle for the base en/decoding

编辑:从理论上讲,我们必须添加重复字母的附加位(“E”)。否则它只会导致其他整数的并发症!

所以我真的不知道如何解决这个问题,任何帮助都将非常感激。 :)

2 个答案:

答案 0 :(得分:0)

这是一个(相当强力)的解决方案:

这简单地迭代现有的编码器,具有更高的“位深度”,直到找到没有重复字母的解决方案。编码深度前置于编码值(否则将无法反转计算,因为您无法知道“BA”是指2(编码为深度B)还是3(编码为深度C)

这并不能保证尽可能低的“位深度”,但考虑到编码方法,它确实使字符串尽可能短。

以下是1到50之间编码和解码数字的演示:

var encode = function(number) {
  if (number == 1) {
    return "A-A"; // hacky workaround for endless loop in messageToCustomBase
  }
  var ret = "";
  var bits = Math.floor(Math.log2(number) + 1); // minimum depth required for this number
  var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

  for (var i = bits; i < 26; i++) {
    var bitIdentifier = chars.charAt(i - 1);
    var encoded = messageToCustomBase(number, chars.substr(0, i));
    if (encoded.match(/(.)\1/)) {
      // duplicate letters found, keep looking
    } else {
      return bitIdentifier + "-" + encoded
    }
  }
}

var decode = function(m) {
  if (m === 'A-A') {
    return 1
  } // hack again
  var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  var parts = m.split('-');
  var charset = chars.substr(0, parts[0].charCodeAt(0) - 64);
  return customBaseToMessage(parts[1], charset)
}

// exactly as your original code:
function messageToCustomBase(message, charset) {
  var base = charset.length,
    integer = message,
    result = ""
  do {
    var index = integer % base
    result = charset[index] + result
    integer = parseInt(integer / base)
  } while (integer > 0)
  return result
}

function customBaseToMessage(message, charset) {
  var base = charset.length,
    result = 0
  for (var i = 0; i < message.length; i++)  {
    var index = charset.indexOf(message[i])
    result = result * base + index
  }
  return result
}

// encode numbers for testing:
for (var i = 1; i < 51; i++) {
  console.log(i, encode(i), decode(encode(i)));
}

答案 1 :(得分:0)

你可以在第一个循环之后坚持使用base 3,其中可用的字符是你没有用于前一个字符的三个字符。

作为编码代码的修改,这看起来像

function messageToCustomBase(message, charset) {
  var base = charset.length,
      integer = message,
      result = "",
      previous_index = null

  var index = integer % base
  result = charset[index] + result
  integer = parseInt(integer/base)
  previous_index = index

  while (integer > 0) {
    var index = integer % (base - 1)
    if (index >= previous_index) {
      index++
    }
    result = charset[index] + result
    integer = parseInt(integer/(base - 1))
    previous_index = index
  }
  return result   
}

这非常接近最佳,但并不完全。原因是最左边的字符的索引永远不会为零。基本上,它正在进行基本(3..4)的“正确”转换,并且拒绝以0开头的表示。如果你愿意放弃,你可以平均缩短一点。