2011-06-15 45 views
6

數字的短字符串我有一個像這樣的字符串:如何快速編碼,然後壓縮包含在C#

000101456890 
348324000433 
888000033380 

他們是字符串都是相同的長度,它們只包含數字。

我想找到一種方法來編碼,然後ompress(減少長度)的字符串。壓縮算法需要壓縮爲ASCII字符,因爲這些字符將用作網頁鏈接。

因此,例如:

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

有沒有一些方法,我能做到這一點,有些方法會做快速壓縮的工作。

感謝,

+1

是不壓縮包含數字的字符串以將其存儲爲數字而不是字符串的最簡單方法? – AntonyW 2011-06-15 10:29:30

+0

@AntonyW - 我在問題中添加了一些內容。希望這解釋得更好 – czhili 2011-06-15 10:33:23

回答

8

要做到這一點只是,你可以考慮每一個long(充足的房間裏有),和十六進制編碼; ,讓你:

60c1bfa 
5119ba72b1 
cec0ed3264 

基地-64將是短,但你需要把它看成大端(注意:大多數.NET是小端)和忽略前導0字節。這就給了你:

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

有沒有一種方法可以使用密鑰進行編碼,以確保鏈接安全。我現在所擁有的是,如果用戶知道一個鏈接,他們可以通過增加數字來查看下一個鏈接。我想嘗試通過編碼來實現這一點。 – czhili 2011-06-15 10:44:07

+14

@czhili你是否有機會在花旗銀行工作?要做的正確的事情是***驗證鏈接***。您也可能會考慮非連續的標識符,但即使如此,您仍應*驗證訪問權限。最後,當然,你可以添加一些基於密鑰的加擾 - 但你應該*仍然*驗證訪問。 – 2011-06-15 10:46:06

+0

@czhili評論:WTF。更長的解釋:如果重要的是一個人可以通過增加數量來獲得新的「鏈接」,那麼你的鏈接就會非常錯誤。 – 2011-06-15 11:05:45

2

我不知道基地64是URL安全的,因爲它有「/」在其索引表(在選擇的答案提供的包裝功能會產生非網址安全的字符串)。

你可以考慮用更友好的URL或使用其他基礎來替換'/'符號。例如,基地62將在這裏完成。

這裏是一個通用的代碼轉換來回從十進制到任何數字基< = 64(它可能更快然後轉換爲字節,然後使用Convert.ToBase64String()):

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

你可以交換幾個最後的base-64字母字符...... – 2011-06-15 15:52:02

+0

是的,你可以考慮用更友好的URL來替換'/'符號。 – nakhli 2011-06-15 16:29:17