Return fixed length std::string from integer value
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 char
s is
sufficient for most current machines).
Related videos on Youtube
Comments
-
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 -127so 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 -110so 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 over 11 yearsThe code looks correct, but wow, you sure complicated this a little :)
-
samantha over 11 yearsHi 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 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 over 11 yearsYour 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 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 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
andauto
. Anyways, thanks for pointing this out to samantha -
Steve Jessop over 11 yearsAnd if you're worried about someone passing
width > 100
in the last case, you could use avector<char>
instead of thatchar[100]
, with size either equal to the width or equal to the width+1. -
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 ofsnprintf
, if necessary. -
samantha over 11 yearsbeing 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 over 11 years
'0'
is a character literal, not a string, andchar
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 over 11 yearsActually, 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 anint
, not achar
. It has the same value as the char'0'
, but different type.std::string
has anoperator+=(char)
but nooperator+=(int)
, so the int is converted back to char before it's appended to the string. -
Steve Jessop over 11 yearsDarn 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. over 5 yearsThis solution does not return a
std::string
! But exchanging thestd::cout
for astd::stringstream
will lead to the desired solution.