Return fixed length std::string from integer value

14,994

Solution 1

I have nothing against the versions that use streams, but you can do it all yourself more simply than your code:

std::string fixedLength(int value, int digits = 3) {
    unsigned int uvalue = value;
    if (value < 0) {
        uvalue = -uvalue;
    }
    std::string result;
    while (digits-- > 0) {
        result += ('0' + uvalue % 10);
        uvalue /= 10;
    }
    if (value < 0) {
        result += '-';
    }
    std::reverse(result.begin(), result.end());
    return result;
}

Solution 2

How about using std::ostringstream and the standard output formatting manipulators?

std::string makeFixedLength(const int i, const int length)
{
    std::ostringstream ostr;

    if (i < 0)
        ostr << '-';

    ostr << std::setfill('0') << std::setw(length) << (i < 0 ? -i : i);

    return ostr.str();
}

Solution 3

You can use I/O manipulators to set the width that you need, and fill with zeros. For example, this program prints 00123:

#include <iostream>
#include <iomanip>

using namespace std;

int main() {
    cout << setfill('0') << setw(5) << 123 << endl;
    return 0;
}

You have to take care of the negative values yourself, though: cout << setfill('0') << setw(5) << -123 << endl prints 0-123, not -0123. Check if the value is negative, set the width to N-1, and add a minus in front.

Solution 4

Note that your examples contradict your description: if the value is -9, and the fixed length is 3, should the output be "-009" (as in your example), or "-09" (as you describe)? If the former, the obvious solution is to just use the formatting flags on std::ostringstream:

std::string
fixedWidth( int value, int width )
{
    std::ostringstream results;
    results.fill( '0' );
    results.setf( std::ios_base::internal, std::ios_base::adjustfield );
    results << std::setw( value < 0 ? width + 1 : width ) << value;
    return results.str();
}

For the latter, just drop the conditional in the std::setw, and pass width.

For the record, although I would avoid it, this is one of the rare cases where printf does something better than ostream. Using snprintf:

std::string
fixedWidth( int value, int width )
{
    char buffer[100];
    snprintf( buffer, sizeof(buffer), "%.*d", width, value );
    return buffer;
}

You'd probably want to capture the return value of snprintf and add some error handling after it, just in case (but 100 chars is sufficient for most current machines).

Share:
14,994

Related videos on Youtube

samantha
Author by

samantha

I am graduate software developer

Updated on June 04, 2022

Comments

  • samantha
    samantha over 1 year

    Problem -> To return fixed length string to std::string*.
    Target machine -> Fedora 11 .

    I have to derive a function which accepts integer value and return fixed lenght string to a string pointer;
    for example -> int value are in range of 0 to -127

    so for int value 0 -> it shoud display 000
    for value -9 -> it should return -009
    for value say -50 -> it should return -050
    for value say -110 -> it should return -110

    so in short , lenght should be same in all cases.

    What I have done : I have defined the function according to the requirement which has shown below.

    Where I need help: I have derived a function but I am not sure if this is correct approach. When I test it on standalone system on windows side , the exe stopped working after sometimes but when I include this function with the overall project on Linux machine , it works flawlessly.

        /* function(s)to implement fixed Length Rssi */
     std::string convertString( const int numberRssi, std::string addedPrecison="" )
     {
         const std::string         delimiter   =   "-";
                    stringstream   ss;
    
         ss  << numberRssi ;
         std::string tempString = ss.str();
         std::string::size_type found = tempString.find( delimiter );
         if( found == std::string::npos )// not found
         {
             tempString = "000";
         }
         else
         {
             tempString = tempString.substr( found+1 );
             tempString = "-" +addedPrecison+tempString ;
         }
         return  tempString;
    
     }
    
     std::string stringFixedLenght( const int number )
     {
         std::string str;
         if( (number <= 0) && (number >= -9) )
           {
               str = convertString( number, "00");
           }
           else if( (number <= -10) && (number >= -99) )
           {
               str = convertString( number, "0");
           }
           else
           {
               str= convertString(number, "");
           }
         return str;
     }
    // somewhere in the project calling the function
    ErrorCode A::GetNowString( std::string macAddress, std::string *pString )
    {
        ErrorCode result = ok;
        int lvalue;
        //some more code like iopening file and reading file 
        //..bla
        // ..bla     
        // already got the value in lvalue ;
    
        if( result == ok )
        {
             *pString = stringFixedLenght( lValue );
        }
    
        // some more code
    
        return result;
    
    }
    
    • jrok
      jrok over 11 years
      The code looks correct, but wow, you sure complicated this a little :)
    • samantha
      samantha over 11 years
      Hi Guys, Thanks everyone for the suggestion, I must say I have definetely learned few new things. Thanks . Though, I am just wondering, if my code is alright and is feasible(somehow) , do I still need to change it?
    • Steve Jessop
      Steve Jessop over 11 years
      @samantha: if nobody can find a reason that it's invalid, and it gives the right answers then I would say no, you don't have to change it. But a desirable property of code is that it not just work, but that anyone reading it can easily see that it works. Also that anyone who wants to change it in future can easily see how it works. For that reason, simpler code is usually preferred. Spending hours making fairly simple code into even simpler code is often a poor investment of time, though, so you have to make a judgement how much to polish things.
  • samantha
    samantha over 11 years
    Your code very clean and concise. Thanks for the code. But I guess I am using old complier and getting few error.: ‘to_string’ is not a member of ‘std’ && error: ‘mag’ does not name a type
  • Steve Jessop
    Steve Jessop over 11 years
    @samantha: those errors are both because phresnel has used C++11 features. Your compiler isn't necessarily "old", but you aren't using its incomplete implementation of the new standard. No compiler has finished implementing C++11 yet, so you're in the majority.
  • Sebastian Mach
    Sebastian Mach over 11 years
    @SteveJessop: Otoh, if you are in a certain target audience, say g++ users, the probability isn't too low you have to_string and auto. Anyways, thanks for pointing this out to samantha
  • Steve Jessop
    Steve Jessop over 11 years
    And if you're worried about someone passing width > 100 in the last case, you could use a vector<char> instead of that char[100], with size either equal to the width or equal to the width+1.
  • James Kanze
    James Kanze over 11 years
    @SteveJessop or +2, to account for the a minus sign and the trailing '\0'. Yes, that would be a definite improvement. And you could resize the vector according to the return value of snprintf, if necessary.
  • samantha
    samantha over 11 years
    being new to C++, could you please explain me the line " result += ('0' + uvalue % 10); " . I understand reminder but failed to understand how appending reminder to '0' produce o/p ( for 1 st iterator) as say 9 for value 59 while i thought it should be 09 and so on?
  • Steve Jessop
    Steve Jessop over 11 years
    '0' is a character literal, not a string, and char in C++ is an integer type. The + is integer addition, so '0' + 0 is '0', '0' + 1 is '1', and so on. Then the += appends the result to the string.
  • Steve Jessop
    Steve Jessop over 11 years
    Actually, there's slightly more to it, but understand the above before you start on this. In fact, arithmetic is always done in a type at least as big as int, so the result of '0' + 0 is an int, not a char. It has the same value as the char '0', but different type. std::string has an operator+=(char) but no operator+=(int), so the int is converted back to char before it's appended to the string.
  • Steve Jessop
    Steve Jessop over 11 years
    Darn that pesky minus sign, in the course of writing my answer I forgot whether it was included in the count twice, and I've also forgotten whether it's included in the width of "%.*d". It's extremely bad form, but sometimes I do just want to add an unexplained 10 or 16 bytes to string buffer sizes, to be on the "safe" side.
  • J. D.
    J. D. over 5 years
    This solution does not return a std::string! But exchanging the std::cout for a std::stringstream will lead to the desired solution.