2015-11-18 64 views
1

我是一個初學者愛好者,並且一直在我的代碼中研究一個問題。我的代碼很醜陋,效率很低,主要是因爲我缺乏經驗。不過,我喜歡這個東西。給定一個字符串轉換爲4字節塊的十六進制... C#

問題:給出一個字符串,我可以成功轉換爲十六進制。然而,我希望給定的字符串(儘管它的長度)被轉換爲十六進制的4字節塊。對於字符串大於一個字節但小於4個字節的情況,我想在字符串的右側填充「0」。我發現只有部分成功,只要我操作PadRight方法的totalWidth參數即可。我怎樣才能達到我所追求的目標,而不需要額外的零碎塊?

請看到確切的代碼示例我使用下面:

// create a char array using the string provided to the encoder method 
     char[] arrayCharValues = strMessage.ToCharArray(); 

     // create stringbuilder object 
     StringBuilder sb = new StringBuilder(); 

     // iterate through each char and convert it to int32 then to Hex then append to stringbuilder object. 
     foreach (char c in arrayCharValues) 
     { 
      // convert char to int32 
      int intCharToNumVal = Convert.ToInt32(c); 
      // convert int32 to hex 
      string strNumToHexVal = String.Format("{0:X2}", intCharToNumVal); 
      // append hex value to string builder object 
      sb.Append(strNumToHexVal); 
     } 

     string s = sb.ToString(); 

     if (s.Length % 8 == 0) 
     { 
      var list = Enumerable 
      .Range(0, s.Length/8) 
      .Select(i => s.Substring(i * 8, 8)) 
      .ToList(); 
      var res = string.Join(" ", list); 

      // DEBUG: echo results for testing. 
      Console.WriteLine(""); 
      Console.WriteLine("String provided: {0}", strMessage); 
      Console.WriteLine("String provided total length: {0}", s.Length); 
      Console.WriteLine("Hex equivalent of string provided: {0}", sb.ToString()); 
      Console.WriteLine("Hex in 8-digit chunks: {0}", res.ToString()); 
      Console.WriteLine("======================================================"); 
     } 
     else 
     { 
      int intDivisibleByEight = s.Length % 8; 
      int intPadRight = (8 - intDivisibleByEight)/2; 
      char pad = '0'; 
      //BUG: doesn't know how to handle anything over 16 bits. If I use an input string of "coolsssss" i get 636F6F6C 73737373 73000000 00000000 
      //BUG: <cont'd> if i use the same input string and change the PadRight(32,pad) to PadRight(16,pad) i get 636F6F6C 73737373 and the final chunk is ignored. 
      //BUG: <cont'd> I want it to work as it does with the PadRight(32, pad) method but, I want it to ignore the all zeros chunk(s) that may follow. 
      //NOTE: int totalWidth = the number of characters i nthe resulting string, equal to the number of original characters plus any additional padding characters. 
      s = s.PadRight(32, pad); 
      var list = Enumerable 
       .Range(0, s.Length/8) 
       .Select(i => s.Substring(i * 8, 8)) 
       .ToList(); 
      var res = string.Join(" ", list); 

      // DEBUG: echo results for testing. 
      Console.WriteLine(""); 
      Console.WriteLine("String provided: {0}", strMessage); 
      Console.WriteLine("String provided total length: {0}", s.Length); 
      Console.WriteLine("Hex equivalent of string provided: {0}", sb.ToString()); 
      Console.WriteLine("Hex in 8-digit chunks: {0}", res.ToString()); 
      Console.WriteLine("======================================================"); 
     } 
+0

爲什麼不在你轉換之前填充你的輸入字符串?然後你的轉換器函數可以假設所有的字符串都是(例如8)的倍數,你不必擔心類似的代碼分割。 –

+0

感謝您的提示。我會嘗試以下提供的示例。 –

回答

1

雖然所有這些.Range.Select很有趣,有時更容易恢復到簡單的老的週期。分塊結果不需要hexedString,我添加它只是爲了顯示不需要分塊時的差異。

string strMessage = "coolsssss"; 


    string hexedString = string.Join("", strMessage.Select(c => String.Format("{0:X2}", (int)c))) 
          .PadRight((strMessage.Length + 3)/4 * 8, '0'); 


    StringBuilder sb = new StringBuilder(strMessage.Length * 9/4 + 10); 
    int count = 0; 
    foreach (char c in strMessage) 
    { 
     if (count == 4) 
     { 
      sb.Append(" "); 
      count = 0; 
     } 
     sb.Append(String.Format("{0:X2}", (int)c)); 
     count++; 
    } 
    for (int i = 0; i < (4 - count) % 4; ++i) 
    { 
     sb.Append("00"); 
    } 


    // DEBUG: echo results for testing. 
    Console.WriteLine(""); 
    Console.WriteLine("String provided: {0}", strMessage); 
    Console.WriteLine("Hex equivalent of string provided: {0}", hexedString); 
    Console.WriteLine("Hex in 8-digit chunks: {0}", sb.ToString()); 
    Console.WriteLine("======================================================"); 

編輯:

由於提問者@GabrielAlicea,我加了一些解釋。

new StringBuilder(strMessage.Length * 9/4 + 10); 

這基本上創建StringBuilder與內存預先分配到所需的大小。我們從4個字母加空格得到8位數字,這裏9/4來自。加一些填充到四。計算並不準確,如果你願意的話,你可以做到。預先分配動態增長的對象(如List,StringBuilder,Dictionary ...)是一種很好的習慣,如果您事先知道大小。列表例如在內部使用數組。填充後,它會獲得兩倍大小的數組,並將所有內容複製到其中。當你事先知道必要的尺寸時,這是浪費時間。使用StringBuilder它會更復雜(並取決於.net版本),但預分配無論如何都是個好主意。

(int i = 0; i < (4 - count) % 4; ++i) 

計數是最後一個塊中的字母數。我們爲每個丟失的字母添加兩個零,這意味着(4 - count)次。它的工作原理除空字符串外,其中count爲0,(4 - count)等於4.所以我加了% 4來處理這個特定的情況。

你的代碼,你可能想這樣寫:

int intPadRight = 8 - intDivisibleByEight; 

這:

s = s.PadRight(s.Length + intPadRight, pad); 

但你完全可以添加% 8到intPadRight和消除if (s.Length % 8 == 0)

... 
    string s = sb.ToString(); 

    int intDivisibleByEight = s.Length % 8; 
    int intPadRight = (8 - intDivisibleByEight) % 8; 
    char pad = '0'; 
    s = s.PadRight(s.Length + intPadRight, pad); 
    var list = Enumerable 
     .Range(0, s.Length/8) 
     .Select(i => s.Substring(i * 8, 8)) 
     .ToList(); 
    var res = string.Join(" ", list); 

    // DEBUG: echo results for testing. 
    Console.WriteLine(""); 
    Console.WriteLine("String provided: {0}", strMessage); 
    Console.WriteLine("String provided total length: {0}", s.Length); 
    Console.WriteLine("Hex equivalent of string provided: {0}", sb.ToString()); 
    Console.WriteLine("Hex in 8-digit chunks: {0}", res.ToString()); 
    Console.WriteLine("======================================================"); 
+0

這正是我想要的。非常感謝你。你能告訴我在我的代碼中我做錯了什麼嗎?我正在尋找儘可能多的學習,因爲我正在尋找指導。再次感謝! –

+0

另外,當你實例化StringBuilder對象時,你能解釋下面的內容嗎? (strMessage。長度* 9/4 + 10)您還可以提供以下內容: (int i = 0; i <(4 - count)%4; ++ i)預先感謝... –

+0

感謝您的解釋! –

相關問題