问题
There was a passing comment in a book of mine about people inputting commas into integers and messing up your program, but it didn't elaborate. That got me thinking, so I tried writing a little algorithm to take an std::string and remove all non-integer characters. This code compiles but skips over output. Why isn't anything being assigned to newstring? Does if(isdigit(fstring[i])) evaluate to true of the address it's pointing to hold a digit?
//little algorithm to take the non-integers out of a string
//no idea on efficiency
#include <iostream>
#include <string>
int main()
{
std::cout << "Enter a number with non-integer characters: ";
std::string fstring;
getline(std::cin, fstring);
std::string newstring;
int i = 0, x = 0;
while (i != fstring.length())
{
if (isdigit(fstring[i]))
{
newstring[x] = fstring[i];
i++;
x++;
}
else
{
i++;
}
}
std::cout << std::endl;
std::cout << newstring;
system("PAUSE");
}
Secondary question, that perhaps belongs elsewhere: how do you convert a string to an int (or a floating point number)?
回答1:
newstring is of length 0, so newstring[x] where x=0 is actually illegal. You should append to the string using: newstring.append(1, fstring[i])
For the secondary question, look for atoi(), atof(), strtol(0, strtof() functions.
回答2:
Strings are like arrays, but the default constructor for a string creates an empty string. Why should it allocate more memory than it needs? Even if it does, there's no saying how much, or if it will be big enough for a filtered copy of fstring. I'm impressed it doesn't crash.
A simple modification would be to change:
std::string newstring;
to:
std::string newstring(fstring.length(), '\0')
And after the loop add:
newstring.resize(x);
This will ensure that newstring
will have at least enough room (probably more) during the filtration and will be trimmed down to the appropriate size when you are finished filtering. You may also be interested in the std::remove_copy_if function in <algorithm>
.
E.g.
struct isnotdigit { bool operator()(char c) { return !isdigit(c); } };
std::string newstring(fstring.length(), '\0');
std::string::iterator i = std::remove_copy_if(fstring.begin(),
fstring.end(), newstring.begin(), isnotdigit());
newstring.erase(i, newstring.end());
As for converting a string to an integer / float, in addition to atoi
, strtol
, atof
, strtof
, etc. functions already mentioned you can also make using of the iostream library:
#include <sstream>
std::string integer("23");
std::istringstream iss(integer);
int result;
iss >> result;
std::string floatingpoint("3.14");
std::istringstream iss2(floatingpoint);
double result2;
iss2 >> result2;
Also, if you are familiar with the printf family of functions you may be interested in scanf
, sscanf
const char *s = "23";
int result;
sscanf(s, "%d", &result);
回答3:
Expansion on Shing Yip's answer:
To remove non-digits:
#include <iostream>
#include <functional>
#include <string>
#include <algorithm>
using namespace std;
int main() {
string fstring;
getline(cin, fstring);
fstring.erase(
remove_if(fstring.begin(), fstring.end(),
not1(ptr_fun(static_cast<int(*)(int)>(isdigit)))
),
fstring.end()
);
cout << fstring << "\n";
}
I'm not sure why that static_cast is needed, though. I think something's ambiguous about isdigit without it. [Edit: If you don't do "using namespace std" then you don't need it, so it's my fault for being lazy writing example code.]
It's debatable whether this is any simpler than rolling your own loop:
#include <iostream>
#include <string>
using namespace std;
int main() {
string fstring, ins;
getline(cin, ins);
for (string::iterator it = ins.begin(); it != ins.end(); ++it) {
if (isdigit(*it)) fstring.push_back(*it);
}
cout << fstring << "\n";
}
And C++0x will have copy_if, which was left out basically by accident, and is trivial to implement:
#include <iostream>
#include <string>
#include <algorithm>
#include <iterator>
int main() {
std::string fstring, ins;
std::getline(std::cin, ins);
std::copy_if(ins.begin(), ins.end(),
std::back_inserter(fstring), isdigit);
std::cout << fstring << "\n";
}
To convert to int (or float):
int i = boost::lexical_cast<int>(fstring);
Or if you don't have boost:
#include <sstream>
int i = 0;
std::stringstream(fstring) >> i;
Note that you do have to initialize i, otherwise it won't be set if fstring is empty.
回答4:
To remove digits:
fstring.erase(
std::remove_if(fstring.begin(), fstring.end(), &isdigit),
fstring.end());
To convert string to int/float/...:
int n1 = boost::lexical_cast<int>("123");
float n2 = boost::lexical_cast<float>("123.456");
回答5:
- string to floating point number:
You need to #include <cstdlib>
float strtof(const char *nptr, char **endptr);
For example:
float f = strtof("3.4",NULL);
- string to integer
You need to #include <cstdlib>
int atoi(const char *numPtr);
Notice that these are C - functions, not C++, so you need to use the c_str() method on std::string to get the C-string.
const char* c_str ( ) const;
来源:https://stackoverflow.com/questions/816001/removing-non-integers-from-a-string-in-c