Преобразование большой шестнадцатеричной строки в десятичную строку

Мне нужно преобразовать большую (слишком большую для встроенных типов данных) шестнадцатеричную строку в строку с ее десятичным представлением. Например:

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

В настоящее время я использую C++ BigInt Class, который предлагает очень простой способ добиться этого (но только GPL):

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

Есть ли простой способ сделать это преобразование без сторонней арифметической библиотеки? Или вы можете порекомендовать бесплатную (не GPL) альтернативу с такой же простотой (эффективность не имеет значения)?


person Flavio    schedule 19.01.2011    source источник


Ответы (3)


Хорошо, вот общий базовый класс преобразователя. Я написал исходную реализацию на C# и преобразовал ее в C++. Его происхождение .NET все еще может просвечиваться. Не стесняйтесь использовать его по своему усмотрению.

Вы можете использовать его следующим образом:

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

Вывод будет:

10187768649047767717933300899576725832

Этот класс не ограничен шестнадцатеричными цифрами, но будет успешно выполнять перевод между любым основанием, используя любую кодировку базовых цифр.

API

  • BaseConverter::BaseConverter(const std::string& sourceBaseSet, const std::string& targetBaseSet);

    Создает новый экземпляр BaseConverter. Класс преобразует числа, представленные в исходной базе счисления, в целевую базу счисления.

    Конструктор принимает два аргумента string, чтобы указать символы, которые будут использоваться для исходной и целевой систем счисления. Первый символ в строке имеет значение 0, второй — значение 1 и так далее. Пример: символы для восьмеричной системы счисления обычно "01234567", а для шестнадцатеричной системы счисления "0123456789ABCDEF". Любой печатный символ ASCII может использоваться в качестве символа, поэтому вы можете, например. используйте "OI" (вместо "01") для двоичной системы.

    Примечание: основные символы чувствительны к регистру, поэтому символы "0123456789abcdef" не декодируют шестнадцатеричные числа с использованием символов верхнего регистра.

  • std::string BaseConverter::Convert(std::string value) const;
    std::string BaseConverter::Convert(const std::string& value, size_t minDigits) const;

    Преобразует число value в исходной базе счисления в целевую базу счисления и возвращает результат. Вторая перегрузка принимает дополнительный параметр minDigits, чтобы указать минимальное количество цифр в результате. Возвращаемое значение будет дополнено добавлением нуля или более символов, имеющих значение 0 в целевой системе счисления.

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

    Преобразует десятичное число unsigned int в целевое числовое основание.

  • unsigned int BaseConverter::ToDecimal(std::string value) const;

    Преобразует число в исходной системе счисления в десятичное целое число без знака. Примечание: результат будет неправильным, если десятичное значение числа в исходной базовой системе превышает UINT_MAX.

  • static const BaseConverter& BaseConverter::DecimalToBinaryConverter();
    static const BaseConverter& BaseConverter::BinaryToDecimalConverter();
    static const BaseConverter& BaseConverter::DecimalToHexConverter();
    static const BaseConverter& BaseConverter::HexToDecimalConverter();

    Вспомогательные функции, возвращающие экземпляры BaseConverter, подходящие для преобразования между общими системами счисления. Примечание: символы верхнего регистра от A до F используются для шестнадцатеричной системы счисления.

Базовый конвертер.h:

// Arbitrary precision base conversion by Daniel Gehriger <[email protected]>   

#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 <[email protected]>   

#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;
}
person Daniel Gehriger    schedule 19.01.2011
comment
Это круто! Благодарю вас! - person Uy Trieu Vi Tran; 21.06.2021

Вы можете использовать эту функцию для преобразования шестнадцатеричного символа в десятичный символ:

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;
    }
}
person steg    schedule 19.01.2011
comment
Это даст мне только массив с десятичными значениями каждого символа в шестнадцатеричной строке, но мне нужно преобразовать всю строку в одно число. Сложение всех значений невозможно, поскольку конечный результат будет слишком большим для обычных целых чисел. - person Flavio; 19.01.2011

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

person Ash    schedule 19.01.2011
comment
К сожалению, похоже, это не работает, sDec получает то же значение, что и sHex. - person Flavio; 19.01.2011
comment
Вы тестировали образец ввода и вывода, представленный в вопросе? - person Ben Voigt; 19.01.2011
comment
Да, более короткая шестнадцатеричная строка (std::istringstream ( 2A ) ›› std::hex ›› sDec) приводит к такому же поведению. - person Flavio; 19.01.2011
comment
@Flavio: я спрашивал Ашириуса. - person Ben Voigt; 19.01.2011