2015-11-18 5 views
1

Я начинающий энтузиаст и некоторое время изучаю проблему в своем коде. Мой код уродлив и неэффективен, потому что я неопытен. Тем не менее, мне это нравится.Учитывая, что строка преобразуется в hex в 4-байтовых фрагментах ... C#

Проблема: с учетом строки я могу успешно преобразовать в шестнадцатеричный. Тем не менее, я хочу, чтобы данная строка (несмотря на ее длину) была преобразована в 4-байтовые фрагменты в Hex. В ситуациях, когда строка больше байта, но меньше 4-байтов, я хотел бы добавить «0» справа от строки. Я нахожу, что у меня только частичный успех, пока я манипулирую параметром totalWidth для метода PadRight. Как я могу достичь того, что ищу, не имея лишних кусков с нулевым значением в них?

Пожалуйста, смотрите точный образец кода я использую ниже:

// 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 не требуется для chunked result, я добавил его просто, чтобы показать разницу, когда chunking не требуется.

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("======================================================"); 

EDIT:

Как спросил @GabrielAlicea, я добавил некоторые пояснения.

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

Это в основном создает StringBuilder с памятью, предварительно выделенной до необходимого размера. Мы получаем 8 цифр из 4 букв плюс пробел, здесь 9/4. Плюс некоторые дополнения к четырем. Расчет не является точным, вы можете сделать это, если хотите. Хорошая привычка предубирать динамически растущие объекты, такие как List, StringBuilder, Dictionary ... если вы знаете размер заранее. Например, в List List используется массив внутри. Когда он заполняется, он получает массив в два раза больше размера и копирует все в него. Когда вы заранее знаете необходимый размер, это зря время. С StringBuilder это сложнее (и зависит от версии .net), но preallocation - это хорошая идея.

(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

Спасибо за объяснение! –

 Смежные вопросы

  • Нет связанных вопросов^_^