C#中的通用字符串编码器

时间:2010-03-09 19:33:14

标签: c#

我需要的是非常简单,但在重新发明轮子之前,我想知道框架中是否存在类似的东西。

我想从预定义的字符表中编码(和解码)字符串。我有很多字符串包含很少的字符。这是我想要编码的字符串:

CN = 1; PL = 23; VF = 3; VV = 0

此字符串大小为20个字符,因此为20个字节。

在字符串中,我只使用以下字符:cn = 1; p23vf0

共11个字符。那么每个字符只能用4位编码不是吗?减少使用的总字节数为10。

.NET中是否存在可以在参数和引用表数组中使用字符串并返回编码字节的现有方法?

char [] reference =“cn = 1; p23vf0”.ToCharArray(); string input =“cn = 1; pl = 23; vf = 3; vv = 0”;

byte [] encoded = someClass.Encode(输入,引用); string decoding = someClass.Decode(encoded,reference);

Assert.AreEqual(输入,解码);

7 个答案:

答案 0 :(得分:2)

任何压缩算法都使用Huffman encoding。这基本上就是你在这里寻找的东西。该编码不是单独公开的类,它是DeflateStream和GZipStream类算法的一部分。只要你的字符串是合理的大小,你应该使用哪个。如果它们很短,则编码它们没有任何意义。

答案 1 :(得分:2)

有趣的问题......框架中没有任何内置,但可以这样做:

public static byte[] Encode(string input, string reference) {
  int size = 1;
  while ((1 << ++size) < reference.Length);
  byte[] result = new byte[(size * input.Length + 7) / 8];
  new BitArray(
    input
    .Select(c => {
      int index = reference.IndexOf(c);
      return Enumerable.Range(0, size).Select(i => (index & (1 << i)) != 0);
    })
    .SelectMany(a => a)
    .ToArray()
  ).CopyTo(result, 0);
  return result;
}

public static string Decode(byte[] encoded, int length, string reference) {
  int size = 1;
  while ((1 << ++size) < reference.Length);
  return new String(
    new BitArray(encoded)
      .Cast<bool>()
      .Take(length * size)
      .Select((b, i) => new { Index = i / size, Bit = b })
      .GroupBy(g => g.Index)
      .Select(g => reference[g.Select((b, i) => (b.Bit ? 1 : 0) << i).Sum()])
      .ToArray()
  );
}

代码有点复杂,但这是因为它适用于每个字符的任意位数,而不仅仅是四个。

您在问题中编码字符串,但字符串包含十二个不同的字符,而不是十一个:

string reference = "cn=1;pl23vf0";
string input = "cn=1;pl=23;vf=3;vv=0";

byte[] encoded = Encode(input, reference);

要解码字符串,您还需要原始字符串的长度,因为无法从编码数据的长度来判断:

string decoded = Decode(encoded, input.Length, reference);

(或者提供长度,你当然可以引入一个EOF字符,或类似于base64填充数据的填充字符。)

答案 2 :(得分:1)

没有开箱即用的类可以做到这一点,但使用BitArray类的.NET并不太难。 获得位数组后,可以将其转换为字符串或压缩字节表示。

// modify this as appropriate to divide your original input string...
public IEnumerable<string> Divide( string s )
{ 
    for( int i = 0; i < s.Length; i += 2 )
        yield return s.Substring( i, 2 );
}

public IEnumerable<bool> AsBoolArray( byte b )
{
    var i = 4; // assume we only want 4-bits
    while( i-- > 0 )
    {
        yield return (b & 0x01) != 0;
        b >>= 1;
    }
}

// define your own mapping table...
var mappingTable = 
  new Dictionary<string,int>() { {"cn", 1}, {"pl",23}, {"vf",3}, {"vv",0} /*...*/ };
var originalString = "cncnvfvvplvvplpl";

// encode the data by mapping each string to the dictionary...
var encodedData = DivideString( originalString ).Select( s => mappingTable[s] );
// then convert into a bitVector based on the boolean representation of each value...
// The AsBoolArray() method return the 4-bit encoded bool[] for each value
var packedBitVector = 
  new BitArray( encodedData.Select( x => AsBoolArray(x) ).ToArray() );
// you can use BitArray.CopyTo() to get the representation out as a packed int[]

答案 3 :(得分:1)

我认为如果你想最小化字符串的大小,最好在这里使用System.IO.Compression.GZipStream。它非常简单,可能会压缩你的字符串2次以上。

答案 4 :(得分:0)

基类库中没有内置任何内容。你必须建立自己的。

看一下System.Text中的Encoder类 - 一些元素可能会有所帮助。

答案 5 :(得分:0)

StringBuilder课程会有任何帮助吗?

答案 6 :(得分:0)

您可以使用CrytpAPI。这是一个很好的例子,including加密和解密字符串的方法。不过,我认为它不会“压缩”您的数据。