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

本文关键字:字节 转换 十六进制 字符串 一个 | 更新日期: 2023-09-27 18:22:15

我是一个初学者爱好者,最近一直在研究我的代码中的一个问题。我的代码丑陋且效率低下,主要是因为我缺乏经验。然而,我喜欢这个东西。

问题:给定一个字符串,我可以成功地转换为十六进制。然而,我希望给定的字符串(尽管它的长度)能够转换为Hex中的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("======================================================");
        }

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

虽然所有这些.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。。。如果你事先知道尺寸。例如,List在内部使用数组。当填充时,它会得到两倍大小的数组,并将所有内容复制到其中。当您提前知道必要的大小时,这是在浪费时间。使用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("======================================================");