给定一个字符串转换为4字节块的十六进制... C#

问题描述:

我是一个初学者爱好者,并且一直在我的代码中研究一个问题。我的代码很丑陋,效率很低,主要是因为我缺乏经验。不过,我喜欢这个东西。给定一个字符串转换为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

感谢您的提示。我会尝试以下提供的示例。 –

虽然所有这些.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

+0

感谢您的解释! –