【问题标题】:Direct convertation between ascii byte[] and intascii byte[] 和 int 之间的直接转换
【发布时间】:2016-07-17 16:42:43
【问题描述】:

我有一个从网络读取字节的程序。有时,这些字节是十进制或十六进制形式的整数的字符串表示形式。

通常,我会用类似的东西来解析它

var s=Encoding.ASCII.GetString(p.GetBuffer(),0,(int)p.Length);                                      
int.TryParse(s, out number);

我觉得这很浪费,因为它必须为字符串分配内存而不需要它。

有没有更好的方法可以在 c# 中做到这一点?

更新

我看到了一些使用BitConverter 类的建议。这不是我需要的。 BitConverter 会将 int(4 字节)的二进制表示转换为 int 类型,但由于 int 是 ascii 格式,此处不适用。

【问题讨论】:

  • 虽然您可以通过硬编码 ASCII 数字与其原始字节等效值之间的映射来手动解析字节,但除非您有令人信服的理由相信这是性能瓶颈,否则这可能不值得。
  • 您是否尝试过基本的 .NET 支持来将字节数组转换为另一种类型? msdn.microsoft.com/en-us/library/bb384066.aspx

标签: c# parsing binary bytearray


【解决方案1】:

我怀疑它会对性能或内存消耗产生重大影响,但您可以相对轻松地做到这一点。一种转换十进制数的实现如下所示:

private static int IntFromDecimalAscii(byte[] bytes)
{
    int result = 0;

    // For each digit, add the digit's value times 10^n, where n is the
    // column number counting from right to left starting at 0.
    for(int i = 0; i < bytes.Length; ++i)
    {
        // ASCII digits are in the range 48 <= n <= 57. This code only
        // makes sense if we are dealing exclusively with digits, so
        // throw if we encounter a non-digit character
        if(bytes[i] < 48 || bytes[i] > 57)
        {
            throw new ArgumentException("Non-digit character present", "bytes");
        }

        // The bytes are in order from most to least significant, so
        // we need to reverse the index to get the right column number
        int exp = bytes.Length - i - 1;

        // Digits in ASCII start with 0 at 48, and move sequentially
        // to 9 at 57, so we can simply subtract 48 from a valid digit
        // to get its numeric value
        int digitValue = bytes[i] - 48;

        // Finally, add the digit value times the column value to the
        // result accumulator
        result += digitValue * (int)Math.Pow(10, exp);
    }

    return result;
}

这也可以很容易地适应转换十六进制值:

private static int IntFromHexAscii(byte[] bytes)
{
    int result = 0;
    for(int i = 0; i < bytes.Length; ++i)
    {
        // ASCII hex digits are a bit more complex than decimal.
        if(bytes[i] < 48 || bytes[i] > 71 || (bytes[i] > 57 && bytes[i] < 65))
        {
            throw new ArgumentException("Non-digit character present", "bytes");
        }
        int exp = bytes.Length - i - 1;

        // Assume decimal first, then fix it if it's actually hex.
        int digitValue = bytes[i] - 48;
        // This is safe because we already excluded all non-digit
        // characters above
        if(bytes[i] > 57) // A-F
        {
            digitValue = bytes[i] - 55;
        }

        // For hex, we use 16^n instead of 10^n
        result += digitValue * (int)Math.Pow(16, exp);
    }

    return result;
}

【讨论】:

  • 糟糕!你当然是对的。编辑以明确第一种方法仅处理小数。
  • +1 指出这很可能不会对性能或内存消耗产生实质性影响。另外,CLR 是string interning,所以“它必须分配内存”不一定正确。
  • 关于字符串实习的好点,但值得指出的是,虽然 CLR 支持 字符串实习,但在运行时生成的字符串通常不会被实习。 This demo 表明运行时支持 .netfiddle 不实习运行时字符串。
  • 有趣,不知道。所以我链接的官方 MSDN 文档是完全错误的。 "(...) 包含对程序中以编程方式声明或创建的每个唯一文字字符串的单个引用。因此,具有特定值的文字字符串的实例仅在系统中存在一次。(...) " 不正确,真的。
【解决方案2】:

好吧,通过避免像这样的 s 声明,您可以少一点浪费(至少在源代码字符的数量上):

int.TryParse(Encoding.ASCII.GetString(p.GetBuffer(),0,(int)p.Length), out number);

但是,我认为获得加速的唯一其他真正方法是按照评论者的建议进行操作,并将映射硬编码到字典或其他东西中。如果您必须经常这样做,这可能会节省一些时间,但可能不值得付出努力......

【讨论】:

  • 为什么不直接使用 BitConverter 类?
  • 这被建议作为答案并被删除,因为 bitconverter 不会将数据的字符串表示形式(如 -1 的文字“ffffffff”字符串)转换为整数。
  • 像这样写下来不会对需要为字符串分配的内存做任何事情。我试图避免这种情况
  • 是的,这是真的。我没有更好的答案,希望其他人有。你能不试试字典方法吗?
  • 旁注:请不要将问题复制到答案中(已编辑)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-03
  • 2011-06-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-17
相关资源
最近更新 更多