2011-06-15 13 views
6

sayıları içeren kısa bir dize sıkıştırmak:nasıl çabuk kodlamak ve o zaman bu gibi görünen dizeleri var C#

000101456890 
348324000433 
888000033380 

Hepsi aynı uzunlukta dizeleri ve bunlar yalnızca rakam içerir.

Kodların şifrelenmesi için bir yol bulmayı ve sonra dizeleri sıkıştırmayı (uzunluğunu azaltmayı) bulmayı istiyorum. Sıkıştırma algoritması, web sayfası bağlantıları olarak kullanılacaklarından ASCII karakterlerine sıkıştırmak zorundadır. Örneğin bu şekilde

:

www.stackoverflow.com/000101456890 goes to www.stackoverflow.com/aJks 

bunu yapabileceğimi bir yol var mı, çabuk sıkıştırarak işini yapacağını bazı yöntemi.

sayesinde

+1

değil mi: İşte

< = 64 (o Convert.ToBase64String kullanarak daha sonra bayt dönüştürme ve daha sonra muhtemelen daha hızlı()) herhangi bir rakam tabanına ondalık ileri geri çeviren bir jenerik koddur sayı içeren bir dizeyi sıkıştırmak için en kolay yol bir dizge değil, sayı olarak saklamaktır? – AntonyW

+0

@AntonyW - Bu soruya bazı şeyler ekledim. Umarım bunu daha iyi açıklar – czhili

cevap

8

basitçe, bir long (orada bol oda) olarak her düşünebiliriz bunu ve altıgen-kodlamak için;

60c1bfa 
5119ba72b1 
cec0ed3264 

temel 64 daha kısa olacağını, ancak o kadar büyük endian (çoğu .NET olan küçük-endian dikkat edin) bakmak ve 0 bayt lider görmezden gerekir: o verir. Bu size verir: Örneğin

Bgwb+g== 
URm6crE= 
zsDtMmQ= 

:

static void Main() 
    { 
     long x = 000101456890L, y = 348324000433L, z = 888000033380L; 

     Console.WriteLine(Convert.ToString(x, 16)); 
     Console.WriteLine(Convert.ToString(y, 16)); 
     Console.WriteLine(Convert.ToString(y, 16)); 

     Console.WriteLine(Pack(x)); 
     Console.WriteLine(Pack(y)); 
     Console.WriteLine(Pack(z)); 

     Console.WriteLine(Convert.ToInt64("60c1bfa", 16).ToString().PadLeft(12, '0')); 
     Console.WriteLine(Convert.ToInt64("5119ba72b1", 16).ToString().PadLeft(12, '0')); 
     Console.WriteLine(Convert.ToInt64("cec0ed3264", 16).ToString().PadLeft(12, '0')); 

     Console.WriteLine(Unpack("Bgwb+g==").ToString().PadLeft(12, '0')); 
     Console.WriteLine(Unpack("URm6crE=").ToString().PadLeft(12, '0')); 
     Console.WriteLine(Unpack("zsDtMmQ=").ToString().PadLeft(12, '0')); 

    } 
    static string Pack(long value) 
    { 
     ulong a = (ulong)value; // make shift easy 
     List<byte> bytes = new List<byte>(8); 
     while (a != 0) 
     { 
      bytes.Add((byte)a); 
      a >>= 8; 
     } 
     bytes.Reverse(); 
     var chunk = bytes.ToArray(); 
     return Convert.ToBase64String(chunk); 
    } 
    static long Unpack(string value) 
    { 
     var chunk = Convert.FromBase64String(value); 
     ulong a = 0; 
     for (int i = 0; i < chunk.Length; i++) 
     { 
      a <<= 8; 
      a |= chunk[i]; 
     } 
     return (long)a; 
    } 
+0

Bağlantıları güvenli hale getirmek için bir anahtar ile kodlayabileceğim bir yol var mı? Şu anda sahip olduğum şey, bir kullanıcı bir bağlantıyı bilirse, bir sonraki numarayı sadece numarayı çevirerek görebilir. Kodlayarak bunu imkansız hale getirmek istiyorum. – czhili

+14

@czhili Citibank için herhangi bir şansla çalışıyor musunuz? Orada yapılacak doğru şey *** bağlantılara erişimi doğrulamak ***. Ayrıca ardışık olmayan tanımlayıcıları da düşünebilirsiniz, ancak o zaman bile * hala * erişimi doğrulamanız gerekir. Son olarak, emin; bazı tuşlara dayalı şifreleme ekleyebilirdiniz - ancak yine de * girişi * doğrulamanız gerekir. –

+0

@czhili comment: WTF. Daha uzun bir açıklama: eğer bir kişi yeni bir 'link' almak için numarayı açabilirse, o zaman yaptıklarınız çok yanlıştır. –

2

Ben seçilmiş cevap sağlanan '/' onun indeks tablosunda (paket işlevi vardır beri Base 64 url ​​güvenli emin değilim URL güvenli olmayan dizeler üretecektir).

'/' simgesini daha fazla url ile değiştirmeyi veya başka bir temel kullanmayı düşünebilirsiniz. Baz 62, örneğin burada yapacağız.

static void Main() 
{ 
    Console.WriteLine(Decode("101456890", 10)); 
    Console.WriteLine(Encode(101456890, 62)); 
    Console.WriteLine(Decode("6rhZS", 62)); 
    //Result: 
    //101456890 
    //6rhZS 
    //101456890 
} 

public static long Decode(string str, int baze) 
{ 
    long result = 0; 
    int place = 1; 
    for (int i = 0; i < str.Length; ++i) 
    { 
     result += Value(str[str.Length - 1 - i]) * place; 
     place *= baze; 
    } 

    return result; 
} 

public static string Encode(long val, int baze) 
{ 
    var buffer = new char[64]; 
    int place = 0; 
    long q = val; 
    do 
    { 
     buffer[place++] = Symbol(q % baze); 
     q = q/baze; 
    } 
    while (q > 0); 

    Array.Reverse(buffer, 0, place); 
    return new string(buffer, 0, place); 
} 

public static long Value(char c) 
{ 
    if (c == '+') return 62; 
    if (c == '/') return 63; 
    if (c < '0') throw new ArgumentOutOfRangeException("c"); 
    if (c < ':') return c - '0'; 
    if (c < 'A') throw new ArgumentOutOfRangeException("c"); 
    if (c < '[') return c - 'A' + 10; 
    if (c < 'a') throw new ArgumentOutOfRangeException("c"); 
    if (c < '{') return c - 'a' + 36; 
    throw new ArgumentOutOfRangeException("c"); 
} 

public static char Symbol(long i) 
{ 
    if (i < 0) throw new ArgumentOutOfRangeException("i"); 
    if (i < 10) return (char)('0' + i); 
    if (i < 36) return (char)('A' + i - 10); 
    if (i < 62) return (char)('a' + i - 36); 
    if (i == 62) return '+'; 
    if (i == 63) return '/'; 
    throw new ArgumentOutOfRangeException("i"); 
} 
+0

Son base-64 alfabe karakterlerinden sadece birkaçını takas edebilirsiniz .... –

+0

Evet, '/' sembolünü daha fazla url dostu bir şeyle değiştirmeyi düşünebilirsiniz. – nakhli

İlgili konular