【问题标题】:Convert large hex string to decimal string将大的十六进制字符串转换为十进制字符串
【发布时间】:2012-03-26 04:16:23
【问题描述】:

我需要将一个大的(对于内置数据类型来说太大)十六进制字符串转换为十进制表示的字符串。例如:

std::string sHex = "07AA17C660F3DD1D2A1B48F1B746C148";
std::string sDec; // should end up with: "10187768649047767717933300899576725832"

我目前正在使用c++ BigInt Class,它提供了一种非常简单的方法来实现这一点(但仅限 GPL):

BigInt::Vin vbiTemp(sHex, 16);
sDec = vbiTemp.toStrDec();

是否有简单的方法可以在没有 3rd 方算术库的情况下进行这种转换?或者您能推荐一个具有类似简单性(效率无关紧要)的免费(非 GPL)替代方案吗?

【问题讨论】:

    标签: c++ arbitrary-precision base-conversion


    【解决方案1】:

    好的,这是一个通用的基本转换器类。我用 C# 编写了原始实现,现在将其转换为 C++。它的 .NET 起源可能仍然闪耀。随意使用它。

    你可以这样使用它:

    const BaseConverter& hex2dec = BaseConverter::HexToDecimalConverter();
    std::cout << hex2dec.Convert("07AA17C660F3DD1D2A1B48F1B746C148");
    

    输出将是:

    10187768649047767717933300899576725832
    

    该类不限于十六进制数字,而是可以使用任何基数编码在任何基数之间进行转换。

    API

    • <strong>BaseConverter::BaseConverter</strong>(const std::string&amp; sourceBaseSet, const std::string&amp; targetBaseSet);

      构造一个新的 BaseConverter 实例。该类在 source 数字基数中表示的数字之间转换为 target 数字基数。

      构造函数采用两个 string 参数来指定用于源和目标数字基数的符号。字符串中的第一个字符的值为 0,第二个字符的值为 1,以此类推。示例:八进制数字基数的符号通常为 "01234567",十六进制符号为 "0123456789ABCDEF"。任何可打印的 ASCII 字符都可以用作符号,因此您可以例如。对二进制系统使用"OI"(而不是"01")。

      注意:基本符号区分大小写,因此符号"0123456789abcdef"解码使用大写字符的十六进制数字。

    • std::string <strong>BaseConverter::Convert</strong>(std::string value) const;
      std::string <strong>BaseConverter::Convert</strong>(const std::string&amp; value, size_t minDigits) const;

      将源数字基数中的数字value 转换为目标数字基数并返回结果。第二个重载需要一个附加参数minDigits 来指定结果中的最小位数。返回的值将通过在目标数字基数中添加零个或多个具有值 0 的符号来填充。

    • std::string <strong>BaseConverter::FromDecimal</strong>(unsigned int value) const;
      std::string <strong>BaseConverter::FromDecimal</strong>(unsigned int value, size_t minDigits) const;

      unsigned int 十进制数转换为目标数基数。

    • unsigned int <strong>BaseConverter::ToDecimal</strong>(std::string value) const;

      将源数字系统中的数字转换为十进制无符号整数注意:如果源基系统中数字的十进制值超过UINT_MAX,结果会出错。

    • static const BaseConverter&amp; <strong>BaseConverter::DecimalToBinaryConverter</strong>();
      static const BaseConverter&amp; <strong>BaseConverter::BinaryToDecimalConverter</strong>();
      static const BaseConverter&amp; <strong>BaseConverter::DecimalToHexConverter</strong>();
      static const BaseConverter&amp; <strong>BaseConverter::HexToDecimalConverter</strong>();

      返回BaseConverter 实例的便利函数适合在常用数字基数之间进行转换。 注意:大写字符 A - F 用于十六进制数基数。

    BaseConverter.h:

    // Arbitrary precision base conversion by Daniel Gehriger <gehriger@linkcad.com>   
    
    #include <string>
    
    class BaseConverter
    {
    public:
        std::string GetSourceBaseSet() const { return sourceBaseSet_; }
        std::string GetTargetBaseSet() const { return targetBaseSet_; }
        unsigned int GetSourceBase() const { return (unsigned int)sourceBaseSet_.length(); }
        unsigned int GetTargetBase() const { return (unsigned int)targetBaseSet_.length(); }
    
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="sourceBaseSet">Characters used for source base</param>
        /// <param name="targetBaseSet">Characters used for target base</param>
        BaseConverter(const std::string& sourceBaseSet, const std::string& targetBaseSet);
    
        /// <summary>
        /// Get a base converter for decimal to binary numbers
        /// </summary>
        static const BaseConverter& DecimalToBinaryConverter();
    
        /// <summary>
        /// Get a base converter for binary to decimal numbers
        /// </summary>
        static const BaseConverter& BinaryToDecimalConverter();
    
        /// <summary>
        /// Get a base converter for decimal to binary numbers
        /// </summary>
        static const BaseConverter& DecimalToHexConverter();
    
        /// <summary>
        /// Get a base converter for binary to decimal numbers
        /// </summary>
        static const BaseConverter& HexToDecimalConverter();
    
        /// <summary>
        /// Convert a value in the source number base to the target number base.
        /// </summary>
        /// <param name="value">Value in source number base.</param>
        /// <returns>Value in target number base.</returns>
        std::string  Convert(std::string value) const;
    
    
        /// <summary>
        /// Convert a value in the source number base to the target number base.
        /// </summary>
        /// <param name="value">Value in source number base.</param>
        /// <param name="minDigits">Minimum number of digits for returned value.</param>
        /// <returns>Value in target number base.</returns>
        std::string Convert(const std::string& value, size_t minDigits) const;
    
        /// <summary>
        /// Convert a decimal value to the target base.
        /// </summary>
        /// <param name="value">Decimal value.</param>
        /// <returns>Result in target base.</returns>
        std::string FromDecimal(unsigned int value) const;
    
        /// <summary>
        /// Convert a decimal value to the target base.
        /// </summary>
        /// <param name="value">Decimal value.</param>
        /// <param name="minDigits">Minimum number of digits for returned value.</param>
        /// <returns>Result in target base.</returns>
        std::string FromDecimal(unsigned int value, size_t minDigits) const;
    
        /// <summary>
        /// Convert value in source base to decimal.
        /// </summary>
        /// <param name="value">Value in source base.</param>
        /// <returns>Decimal value.</returns>
        unsigned int ToDecimal(std::string value) const;
    
    private:
        /// <summary>
        /// Divides x by y, and returns the quotient and remainder.
        /// </summary>
        /// <param name="baseDigits">Base digits for x and quotient.</param>
        /// <param name="x">Numerator expressed in base digits; contains quotient, expressed in base digits, upon return.</param>
        /// <param name="y">Denominator</param>
        /// <returns>Remainder of x / y.</returns>
        static unsigned int divide(const std::string& baseDigits, 
                                   std::string& x, 
                                   unsigned int y);
    
        static unsigned int base2dec(const std::string& baseDigits,
                                     const std::string& value);
    
        static std::string dec2base(const std::string& baseDigits, unsigned int value);
    
    private:
        static const char*  binarySet_;
        static const char*  decimalSet_;
        static const char*  hexSet_;
        std::string         sourceBaseSet_;
        std::string         targetBaseSet_;
    };
    

    BaseConverter.cpp:

    // Arbitrary precision base conversion by Daniel Gehriger <gehriger@linkcad.com>   
    
    #include "BaseConverter.h"
    #include <stdexcept>
    #include <algorithm>
    
    
    const char* BaseConverter::binarySet_ = "01";
    const char* BaseConverter::decimalSet_ = "0123456789";
    const char* BaseConverter::hexSet_ = "0123456789ABCDEF";
    
    BaseConverter::BaseConverter(const std::string& sourceBaseSet, const std::string& targetBaseSet) 
        : sourceBaseSet_(sourceBaseSet)
        , targetBaseSet_(targetBaseSet)
    {
        if (sourceBaseSet.empty() || targetBaseSet.empty())
            throw std::invalid_argument("Invalid base character set");
    }
    
    const BaseConverter& BaseConverter::DecimalToBinaryConverter()
    {
        static const BaseConverter dec2bin(decimalSet_, binarySet_);
        return dec2bin;
    }
    
    const BaseConverter& BaseConverter::BinaryToDecimalConverter()
    {
        static const BaseConverter bin2dec(binarySet_, decimalSet_);
        return bin2dec;
    }
    
    const BaseConverter& BaseConverter::DecimalToHexConverter()
    {
        static const BaseConverter dec2hex(decimalSet_, hexSet_);
        return dec2hex;
    }
    
    const BaseConverter& BaseConverter::HexToDecimalConverter()
    {
        static const BaseConverter hex2dec(hexSet_, decimalSet_);
        return hex2dec;
    }
    
    std::string BaseConverter::Convert(std::string value) const
    {
        unsigned int numberBase = GetTargetBase();
        std::string result;
    
        do
        {
            unsigned int remainder = divide(sourceBaseSet_, value, numberBase);
            result.push_back(targetBaseSet_[remainder]);
        }
        while (!value.empty() && !(value.length() == 1 && value[0] == sourceBaseSet_[0]));
    
        std::reverse(result.begin(), result.end());
        return result;
    }
    
    std::string BaseConverter::Convert(const std::string& value, size_t minDigits) const
    {
        std::string result = Convert(value);
        if (result.length() < minDigits)
            return std::string(minDigits - result.length(), targetBaseSet_[0]) + result;
        else
            return result;
    }
    
    std::string BaseConverter::FromDecimal(unsigned int value) const
    {
        return dec2base(targetBaseSet_, value);
    }
    
    std::string BaseConverter::FromDecimal(unsigned int value, size_t minDigits) const
    {
        std::string result = FromDecimal(value);
        if (result.length() < minDigits)
            return std::string(minDigits - result.length(), targetBaseSet_[0]) + result;
        else
            return result;
    }
    
    unsigned int BaseConverter::ToDecimal(std::string value) const
    {
        return base2dec(sourceBaseSet_, value);
    }
    
    unsigned int BaseConverter::divide(const std::string& baseDigits, std::string& x, unsigned int y)
    {
        std::string quotient;
    
        size_t lenght = x.length();
        for (size_t i = 0; i < lenght; ++i)
        {
            size_t j = i + 1 + x.length() - lenght;
            if (x.length() < j)
                break;
    
            unsigned int value = base2dec(baseDigits, x.substr(0, j));
    
            quotient.push_back(baseDigits[value / y]);
            x = dec2base(baseDigits, value % y) + x.substr(j);
        }
    
        // calculate remainder
        unsigned int remainder = base2dec(baseDigits, x);
    
        // remove leading "zeros" from quotient and store in 'x'
        size_t n = quotient.find_first_not_of(baseDigits[0]);
        if (n != std::string::npos)
        {
            x = quotient.substr(n);
        }
        else
        {
            x.clear();
        }
    
        return remainder;
    }
    
    std::string BaseConverter::dec2base(const std::string& baseDigits, unsigned int value)
    {
        unsigned int numberBase = (unsigned int)baseDigits.length();
        std::string result;
        do 
        {
            result.push_back(baseDigits[value % numberBase]);
            value /= numberBase;
        } 
        while (value > 0);
    
        std::reverse(result.begin(), result.end());
        return result;
    }
    
    unsigned int BaseConverter::base2dec(const std::string& baseDigits, const std::string& value)
    {
        unsigned int numberBase = (unsigned int)baseDigits.length();
        unsigned int result = 0;
        for (size_t i = 0; i < value.length(); ++i)
        {
            result *= numberBase;
            int c = baseDigits.find(value[i]);
            if (c == std::string::npos)
                throw std::runtime_error("Invalid character");
    
            result += (unsigned int)c;
        }
    
        return result;
    }
    

    【讨论】:

    • 这太棒了!谢谢!
    【解决方案2】:

    您可以使用此函数将十六进制字符转换为十进制字符:

    void Hex2Char(const char* szHex, unsigned char& rch)
    {
        rch = 0;
        for(int i=0; i<2; i++)
        {
            if(*(szHex + i) >='0' && *(szHex + i) <= '9')
                rch = (rch << 4) + (*(szHex + i) - '0');
            else if(*(szHex + i) >='A' && *(szHex + i) <= 'F')
                rch = (rch << 4) + (*(szHex + i) - 'A' + 10);
            else
                break;
        }
    }    
    

    你可以用它来转换字符串:

    void HexStrToCharStr(const char* hexStr, unsigned char* decStr, int n)
    {
        unsigned char d_ch;
        for(int i=0; i<n; i++)
        {
            Hex2Char(hexStr+2*i, d_ch);
            decStr[i] = d_ch;
        }
    }
    

    【讨论】:

    • 这只会给我一个数组,其中包含十六进制字符串中每个字符的十进制值,但我需要将整个字符串转换为一个数字。添加所有值是不可能的,因为最终结果对于常规整数来说太大了。
    【解决方案3】:

    std::istringstream (sHex) >> std::hex >> sDec;

    【讨论】:

    • 不幸的是,这似乎不起作用,sDec get 设置为与 sHex 相同的值。
    • 您是否测试了问题中提供的示例输入和输出?
    • 是的,较短的十六进制字符串 ("std::istringstream ("2A" ) >> std::hex >> sDec") 会产生相同的行为。
    • @Flavio:我在问 Ashirius。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-31
    • 1970-01-01
    • 2019-07-27
    • 2018-01-22
    • 2020-11-07
    • 2013-02-07
    相关资源
    最近更新 更多