Ich hatte ziemlich viele Probleme beim Versuch, eine Funktion zu schreiben, die prüft, ob eine Zeichenfolge eine Zahl ist. Für ein Spiel, das ich schreibe, muss ich nur prüfen, ob eine Zeile aus der Datei, die ich gerade lese, eine Zahl ist oder nicht (ich werde wissen, ob es sich dabei um einen Parameter handelt). Ich schrieb die folgende Funktion, von der ich glaube, dass sie reibungslos funktionierte (oder ich habe sie versehentlich bearbeitet, um sie zu stoppen oder ich bin schizophren oder Windows ist schizophren)
bool isParam (string line)
{
if (isdigit(atoi(line.c_str())))
return true;
return false;
}
Die effizienteste Methode wäre, die Zeichenfolge so lange zu durchlaufen, bis Sie ein Zeichen ohne Ziffer finden. Wenn es keine Ziffern gibt, können Sie die Zeichenfolge nicht als Zahl betrachten.
bool is_number(const std::string& s)
{
std::string::const_iterator it = s.begin();
while (it != s.end() && std::isdigit(*it)) ++it;
return !s.empty() && it == s.end();
}
Oder wenn Sie es auf die C++ 11-Weise machen wollen:
bool is_number(const std::string& s)
{
return !s.empty() && std::find_if(s.begin(),
s.end(), [](char c) { return !std::isdigit(c); }) == s.end();
}
Wie in den Kommentaren unten ausgeführt, funktioniert dies nur für positive ganze Zahlen. Wenn Sie negative Ganzzahlen oder Brüche erkennen müssen, sollten Sie auf eine robuste, bibliotheksbasierte Lösung zurückgreifen. Das Hinzufügen von Unterstützung für negative Ganzzahlen ist zwar ziemlich trivial.
Warum das Rad neu erfinden? Die C-Standardbibliothek (auch in C++ verfügbar) verfügt über eine Funktion, die genau dies tut:
char* p;
long converted = strtol(s, &p, 10);
if (*p) {
// conversion failed because the input wasn't a number
}
else {
// use converted
}
Wenn Sie mit Brüchen oder wissenschaftlicher Notation umgehen möchten, verwenden Sie stattdessen strtod
(Sie erhalten ein double
-Ergebnis).
Wenn Sie Hexadezimal- und Oktalkonstanten im C/C++ - Stil ("0xABC"
) zulassen möchten, nehmen Sie stattdessen den letzten Parameter 0
vor.
Ihre Funktion kann dann als geschrieben werden
bool isParam(string line)
{
char* p;
strtol(line.c_str(), &p, 10);
return *p == 0;
}
Mit boost :: lexical_cast können Sie dies auf C++ - Weise tun. Wenn Sie wirklich darauf bestehen, den Boost nicht zu verwenden, können Sie einfach prüfen, was er tut und das tun. Es ist ziemlich einfach.
try
{
double x = boost::lexical_cast<double>(str); // double could be anything with >> operator.
}
catch(...) { oops, not a number }
Bei einem C++ 11-Compiler würde ich für nicht negative Ganzzahlen Folgendes verwenden (beachten Sie den ::
anstelle von std::
):
bool is_number(const std::string &s) {
return !s.empty() && std::all_of(s.begin(), s.end(), ::isdigit);
}
Ich wollte nur diese Idee einbringen, die Iteration verwendet, aber ein anderer Code macht diese Iteration:
#include <string.h>
bool is_number(const std::string& s)
{
return( strspn( s.c_str(), "-.0123456789" ) == s.size() );
}
Es ist nicht so robust, wie es bei der Suche nach einem Dezimalpunkt oder Minuszeichen sein sollte, da es mehr als einen von jedem und an jedem Ort geben kann. Das Gute ist, dass es sich um eine einzige Codezeile handelt und keine Bibliothek eines Drittanbieters erforderlich ist.
Nimm das '.' und '-', wenn nur positive ganze Zahlen zulässig sind.
Mit dieser Lösung können Sie alles von negativen bis positiven Zahlen und sogar Float-Zahlen überprüfen. Wenn Sie den Typ von num
in Ganzzahl ändern, wird ein Fehler angezeigt, wenn die Zeichenfolge einen Punkt enthält.
#include<iostream>
#include<sstream>
using namespace std;
int main()
{
string s;
cin >> s;
stringstream ss;
ss << s;
float num = 0;
ss >> num;
if(ss.good()) {
cerr << "No Valid Number" << endl;
}
else if(num == 0 && s[0] != '0') {
cerr << "No Valid Number" << endl;
}
else {
cout << num<< endl;
}
}
Beweisen Sie: C++ - Programm
Ich würde einen Regex-Ansatz vorschlagen. Eine vollständige Regex-Übereinstimmung (beispielsweise mit boost :: regex ) mit
-?[0-9]+([.][0-9]+)?
würde zeigen, ob die Zeichenfolge eine Zahl ist oder nicht. Dies umfasst positive und negative Zahlen, Ganzzahlen sowie Dezimalzahlen.
Andere Variationen:
[0-9]+([.][0-9]+)?
(nur positiv)
-?[0-9]+
(nur ganze Zahl)
[0-9]+
(nur positive ganze Zahl)
Eine andere Möglichkeit, dies mit der <regex>
-Bibliothek zu tun:
bool is_integer(const std::string & s){
return std::regex_match(s, std::regex("[(-|+)|][0-9]+"));
}
Ich habe festgestellt, dass der folgende Code der robusteste (C++ 11) ist. Es fängt sowohl Ganzzahlen als auch Schwimmer ab.
bool isNumber( std::string token )
{
using namespace std;
return std::regex_match( token, std::regex( ( "((\\+|-)?[[:digit:]]+)(\\.(([[:digit:]]+)?))?" ) ) );
}
Versuche dies:
isNumber(const std::string &str) {
return !str.empty() && str.find_first_not_of("0123456789") == string::npos;
}
Brendan das
bool isNumber(string line)
{
return (atoi(line.c_str()));
}
ist fast in Ordnung.
angenommen, ein String, der mit 0 beginnt, ist eine Zahl Fügen Sie einfach eine Prüfung für diesen Fall hinzu
bool isNumber(const string &line)
{
if (line[0] == '0') return true;
return (atoi(line.c_str()));
}
ofc "123hello" wird wahr zurückgegeben, wie Tony D bemerkt hat.
Hier ist eine Lösung zum Prüfen positiver Ganzzahlen:
bool isPositiveInteger(const std::string& s)
{
return !s.empty() &&
(std::count_if(s.begin(), s.end(), std::isdigit) == s.size());
}
Die einfachste, die ich mir in C++ vorstellen kann
bool isNumber(string s) {
if(s.size()==0) return false;
for(int i=0;i<s.size();i++) {
if((s[i]>='0' && s[i]<='9')==false) {
return false;
}
}
return true;
}
Arbeitscode-Beispiel: https://ideone.com/nRX51Y
bool isNumeric(string s){
if ( !s.empty() && s[0] != '-' )
s = "0" + s; //prepend 0
string garbage;
stringstream ss(s);
ss >> *(auto_ptr<double>(new double)) >> garbage;
/*
//the line above extracts the number into an anonymous variable. it could also be done like this:
double x;
ss >> x >> garbage;
*/
//if there is no garbage return true or else return false
return garbage.empty();
}
wie es funktioniert: Der Stringstream >> overload kann Strings in verschiedene arithmetische Typen konvertieren es liest die Zeichen sequentiell aus dem Stringstream (in diesem Fall ss), bis den Zeichen OR das nächste Zeichen erfüllt nicht die Kriterien, die im Zielvariablentyp gespeichert werden sollen.
beispiel 1:
stringstream ss("11");
double my_number;
ss >> my_number; //my number = 11
beispiel 2:
stringstream ss("011");
double my_number;
ss >> my_number; //my number = 11
beispiel3:
stringstream ss("11ABCD");
double my_number;
ss >> my_number; //my number = 11 (even though there are letters after the 11)
die "Müll" -Variable "":
Warum nicht einfach prüfen, ob die Extraktion in mein double einen gültigen Wert hat, und dann true zurückgeben, wenn dies der Fall ist?
hinweis Das obige Beispiel 3 liest die Nummer 11 trotzdem erfolgreich in die Variable my_number ein, auch wenn der Eingabe-String "11ABCD" ist (was keine Zahl ist).
um diesen Fall zu handhaben, können wir eine weitere Extraktion in eine String-Variable durchführen (die ich als garbage bezeichnet habe), die alles lesen kann, was nach der anfänglichen Extraktion in den String des Double-Puffers übrig geblieben ist. Wenn etwas übrig bleibt, wird es in "Müll" eingelesen, was bedeutet, dass die gesamte übergebene Zeichenfolge keine Zahl war (sie beginnt nur mit einer). In diesem Fall möchten wir false zurückgeben.
die vorangestellte "0" Erklärung ":
der Versuch, ein einzelnes Zeichen in ein Double zu extrahieren, schlägt fehl (gibt 0 in unser Double zurück), verschiebt jedoch weiterhin die Zeichenfolge des Pufferpuffers nach dem Zeichen. In diesem Fall ist unser Garbage Read leer, was dazu führen würde, dass die Funktion falsch true zurückgibt. Um dies zu umgehen, habe ich der Zeichenfolge eine 0 vorangestellt, sodass die Zeichenfolge geändert wurde, wenn die übergebene Zeichenfolge "a" war "0a", so dass die 0 in das Double und "a" in den Müll extrahiert wird.
wenn Sie eine 0 voranstellen, wirkt sich dies nicht auf den Wert der Zahl aus, sodass die Zahl immer noch korrekt in unsere doppelte Variable extrahiert wird.
Wie mir in einer Antwort meiner verwandten Frage offenbart wurde, sollten Sie boost :: conversion :: try_lexical_convert verwenden.
Eine Lösung basierend auf einem Kommentar von kbjorklu ist:
bool isNumber(const std::string& s)
{
return !s.empty() && s.find_first_not_of("-.0123456789") == std::string::npos;
}
Wie bei David Rector's Antwort ist nicht robust gegenüber Zeichenketten mit mehreren Punkten oder Minuszeichen, aber Sie können diese Zeichen entfernen, um nur nach ganzen Zahlen zu suchen.
Ich bin jedoch unschlüssig an einer Lösung, die auf Ben Voigts Lösung basiert und strtod
in cstdlib für Dezimalwerte, wissenschaftliche/technische Notation, hexadezimale Notation (C++ 11) oder sogar INF/INFINITY/NAN ( C++ 11) ist:
bool isNumberC(const std::string& s)
{
char* p;
strtod(s.c_str(), &p);
return *p == 0;
}
um zu überprüfen, ob eine Zeichenfolge eine ganze Zahl oder ein Gleitkommawert ist, können Sie Folgendes verwenden:
#include <sstream>
bool isNumber(string str) {
double d;
istringstream is(str);
is >> d;
return !is.fail() && is.eof();
}
Ich denke, dass dieser reguläre Ausdruck fast alle Fälle behandeln sollte
"^(\\-|\\+)?[0-9]*(\\.[0-9]+)?"
sie können also die folgende Funktion ausprobieren, die sowohl mit Unicode als auch mit ANSI funktioniert.
bool IsNumber(CString Cs){
Cs.Trim();
#ifdef _UNICODE
std::wstring sr = (LPCWSTR)Cs.GetBuffer(Cs.GetLength());
return std::regex_match(sr, std::wregex(_T("^(\\-|\\+)?[0-9]*(\\.[0-9]+)?")));
#else
std::string s = (LPCSTR)Cs.GetBuffer();
return std::regex_match(s, std::regex("^(\\-|\\+)?[0-9]*(\\.[0-9]+)?"));
#endif
}
include <string>
Für die Validierung von Doubles:
bool validateDouble(const std::string & input) {
int decimals = std::count(input.begin(), input.end(), '.'); // The number of decimals in the string
int negativeSigns = std::count(input.begin(), input.end(), '-'); // The number of negative signs in the string
if (input.size() == decimals + negativeSigns) // Consists of only decimals and negatives or is empty
return false;
else if (1 < decimals || 1 < negativeSigns) // More than 1 decimal or negative sign
return false;
else if (1 == negativeSigns && input[0] != '-') // The negative sign (if there is one) is not the first character
return false;
else if (strspn(input.c_str(), "-.0123456789") != input.size()) // The string contains a character that isn't in "-.0123456789"
return false;
return true;
}
Zur Validierung von Ints (mit Negativen)
bool validateInt(const std::string & input) {
int negativeSigns = std::count(input.begin(), input.end(), '-'); // The number of negative signs in the string
if (input.size() == negativeSigns) // Consists of only negatives or is empty
return false;
else if (1 < negativeSigns) // More than 1 negative sign
return false;
else if (1 == negativeSigns && input[0] != '-') // The negative sign (if there is one) is not the first character
return false;
else if (strspn(input.c_str(), "-0123456789") != input.size()) // The string contains a character that isn't in "-0123456789"
return false;
return true;
}
Zur Validierung von nicht signierten Ints
bool validateUnsignedInt(const std::string & input) {
return (input.size() != 0 && strspn(input.c_str(), "0123456789") == input.size()); // The string is not empty and contains characters only in "0123456789"
}
Nachdem ich mir die Dokumentation etwas genauer angesehen hatte, kam ich zu einer Antwort, die meine Bedürfnisse untermauert, für andere aber wahrscheinlich nicht so hilfreich ist. Hier ist es (ohne die nervige Rückkehr wahr und falsche Aussagen zurückgeben :-))
bool isNumber(string line)
{
return (atoi(line.c_str()));
}
Wir können eine stringstream class verwenden.
bool isNumeric(string str)
{
stringstream stream;
double number;
stream<<str;
stream>>number;
return stream.eof();
}
Meine Lösung mit C++ 11 Regex (#include <regex>
), kann für genauere Überprüfungen verwendet werden, wie unsigned int
, double
etc:
static const std::regex INT_TYPE("[+-]?[0-9]+");
static const std::regex UNSIGNED_INT_TYPE("[+]?[0-9]+");
static const std::regex DOUBLE_TYPE("[+-]?[0-9]+[.]?[0-9]+");
static const std::regex UNSIGNED_DOUBLE_TYPE("[+]?[0-9]+[.]?[0-9]+");
bool isIntegerType(const std::string& str_)
{
return std::regex_match(str_, INT_TYPE);
}
bool isUnsignedIntegerType(const std::string& str_)
{
return std::regex_match(str_, UNSIGNED_INT_TYPE);
}
bool isDoubleType(const std::string& str_)
{
return std::regex_match(str_, DOUBLE_TYPE);
}
bool isUnsignedDoubleType(const std::string& str_)
{
return std::regex_match(str_, UNSIGNED_DOUBLE_TYPE);
}
Sie finden diesen Code unter http://ideone.com/lyDtfi . Dieser kann leicht an die Anforderungen angepasst werden.
Diese Funktion kümmert sich um alle möglichen Fälle:
bool AppUtilities::checkStringIsNumber(std::string s){
//Eliminate obvious irritants that could spoil the party
//Handle special cases here, e.g. return true for "+", "-", "" if they are acceptable as numbers to you
if (s == "" || s == "." || s == "+" || s == "-" || s == "+." || s == "-.") return false;
//Remove leading / trailing spaces **IF** they are acceptable to you
while (s.size() > 0 && s[0] == ' ') s = s.substr(1, s.size() - 1);
while (s.size() > 0 && s[s.size() - 1] == ' ') s = s.substr(0, s.size() - 1);
//Remove any leading + or - sign
if (s[0] == '+' || s[0] == '-')
s = s.substr(1, s.size() - 1);
//Remove decimal points
long prevLength = s.size();
size_t start_pos = 0;
while((start_pos = s.find(".", start_pos)) != std::string::npos)
s.replace(start_pos, 1, "");
//If the string had more than 2 decimal points, return false.
if (prevLength > s.size() + 1) return false;
//Check that you are left with numbers only!!
//Courtesy selected answer by Charles Salvia above
std::string::const_iterator it = s.begin();
while (it != s.end() && std::isdigit(*it)) ++it;
return !s.empty() && it == s.end();
//Tada....
}
Vor einigen Monaten habe ich eine Möglichkeit implementiert, um zu bestimmen, ob eine Zeichenfolge eine Ganzzahl, ein Hexadezimalzeichen oder ein Double ist.
enum{
STRING_IS_INVALID_NUMBER=0,
STRING_IS_HEXA,
STRING_IS_INT,
STRING_IS_DOUBLE
};
bool isDigit(char c){
return (('0' <= c) && (c<='9'));
}
bool isHexaDigit(char c){
return ((('0' <= c) && (c<='9')) || ((tolower(c)<='a')&&(tolower(c)<='f')));
}
char *ADVANCE_DIGITS(char *aux_p){
while(CString::isDigit(*aux_p)) aux_p++;
return aux_p;
}
char *ADVANCE_HEXADIGITS(char *aux_p){
while(CString::isHexaDigit(*aux_p)) aux_p++;
return aux_p;
}
int isNumber(const string & test_str_number){
bool isHexa=false;
char *str = (char *)test_str_number.c_str();
switch(*str){
case '-': str++; // is negative number ...
break;
case '0':
if(tolower(*str+1)=='x') {
isHexa = true;
str+=2;
}
break;
default:
break;
};
char *start_str = str; // saves start position...
if(isHexa) { // candidate to hexa ...
str = ADVANCE_HEXADIGITS(str);
if(str == start_str)
return STRING_IS_INVALID_NUMBER;
if(*str == ' ' || *str == 0)
return STRING_IS_HEXA;
}else{ // test if integer or float
str = ADVANCE_DIGITS(str);
if(*str=='.') { // is candidate to double
str++;
str = ADVANCE_DIGITS(str);
if(*str == ' ' || *str == 0)
return STRING_IS_DOUBLE;
return STRING_IS_INVALID_NUMBER;
}
if(*str == ' ' || *str == 0)
return STRING_IS_INT;
}
return STRING_IS_INVALID_NUMBER;
}
Dann können Sie in Ihrem Programm die Zahl einfach in Funktion ihren Typ umwandeln, wenn Sie Folgendes tun:
string val; // the string to check if number...
switch(isNumber(val)){
case STRING_IS_HEXA:
// use strtol(val.c_str(), NULL, 16); to convert it into conventional hexadecimal
break;
case STRING_IS_INT:
// use (int)strtol(val.c_str(), NULL, 10); to convert it into conventional integer
break;
case STRING_IS_DOUBLE:
// use atof(val.c_str()); to convert it into conventional float/double
break;
}
Sie können feststellen, dass die Funktion eine 0 zurückgibt, wenn die Nummer nicht erkannt wurde. Die 0 kann als falsch behandelt werden (wie boolean).
C/C++ - Stil für vorzeichenlose Ganzzahlen mit bereichsbasiertem for
C++ 11:
int isdigits(const std::string & s)
{
for (char c : s) if (!isdigit(c)) return (0);
return (1);
}
Ich schlage eine einfache Konvention vor:
Wenn die Konvertierung nach ASCII> 0 ist oder mit 0 beginnt, handelt es sich um eine Zahl. Es ist nicht perfekt aber schnell.
Etwas wie das:
string token0;
if (atoi(token0.c_str())>0 || isdigit(token0.c_str()[0]) ) { //this is a value
// do what you need to do...
}
<regex>
verwenden. Dieser Code wurde getestet!
bool isNumber(const std::string &token)
{
return std::regex_match(token, std::regex("(\\+|-)?[0-9]*(\\.?([0-9]+))$"));
}
Versuche dies:
bool checkDigit(string str)
{
int n=str.length();
for(int i=0; i < n ; i++)
{
if(str[i]<'0' || str[i]>'9')
return false;
}
return true;
}
Eine weitere Antwort, die stold
verwendet (obwohl Sie auch stof
/stod
verwenden könnten, wenn Sie keine Genauigkeit benötigen).
bool isNumeric(const std::string& string)
{
std::size_t pos;
long double value = 0.0;
try
{
value = std::stold(string, &pos);
}
catch(std::invalid_argument&)
{
return false;
}
catch(std::out_of_range&)
{
return false;
}
return pos == string.size() && !std::isnan(value);
}
Könnten Sie einfach den Rückgabecode von sscanf verwenden, um festzustellen, ob es sich um ein int handelt?
bool is_number(const std::string& s)
{
int value;
int result = sscanf(valueStr.c_str(), "%d", &value);
return (result != EOF && readResult != 0);
}