Jak ustalić, czy ciąg jest liczbą w C ++?


142

Miałem spory problem z napisaniem funkcji, która sprawdza, czy ciąg jest liczbą. W przypadku gry, którą piszę, muszę tylko sprawdzić, czy wiersz z czytanego pliku jest liczbą, czy nie (będę wiedział, czy jest to parametr w ten sposób). Napisałem poniższą funkcję, która moim zdaniem działała płynnie (lub przypadkowo wyedytowałem, aby ją zatrzymać, albo jestem schizofrenikiem lub Windows jest schizofrenikiem):

bool isParam (string line)
{
    if (isdigit(atoi(line.c_str())))
        return true;

    return false;
}

189
Ja cierpię widząc if (expr) return true; return false;! Po prostu napisz return expr;.
ephemient

19
@ephemient Mój styl to robić to samo co Ty. Ale czy to naprawdę wielka sprawa?
Brennan Vincent

2
Twój prototyp funkcji nie wydaje się odpowiedni. Dlaczego nie użyć bool isParam (const string & line)
MikimotoH

4
Tak. Mam zły nawyk pisania długiego stylu podczas nauki nowego języka. Jestem nowy w C ++ i bardziej waham się co do „skrótów” (lub postrzeganych skrótów).
Brendan Weinstein

60
@Brennan Vincent: Tak, to wielka sprawa. To ta sama klasa błędów jak if (expr) return expr; else return expr;, if (expr == true), (if expr != false), lub if ((expr == true) == true). Wszystkie wprowadzają złożoność, która nie jest korzystna dla autora, czytelnika ani kompilatora kodu. Eliminacja zbędnej złożoności nie jest drogą na skróty; to klucz do tworzenia lepszego oprogramowania.
MSalters

Odpowiedzi:


153

Najbardziej wydajnym sposobem byłoby po prostu iterowanie po ciągu, aż znajdziesz znak niebędący cyfrą. Jeśli są jakieś znaki niebędące cyframi, możesz uznać, że ciąg nie jest liczbą.

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();
}

Lub jeśli chcesz to zrobić w C ++ 11 sposób:

bool is_number(const std::string& s)
{
    return !s.empty() && std::find_if(s.begin(), 
        s.end(), [](unsigned char c) { return !std::isdigit(c); }) == s.end();
}

Jak wskazano w komentarzach poniżej, działa to tylko dla dodatnich liczb całkowitych. Jeśli chcesz wykryć ujemne liczby całkowite lub ułamki, powinieneś wybrać bardziej niezawodne rozwiązanie oparte na bibliotekach. Chociaż dodanie obsługi ujemnych liczb całkowitych jest dość trywialne.


6
Nie obsługuje również liczb ujemnych i niecałkowitych. Nie możemy wiedzieć, jakie wymagania są oparte na pytaniu.
Brennan Vincent

76
Możesz również użyć !s.empty() && s.find_first_not_of("0123456789") == std::string::npos;do jednowierszowego C ++ 03.
kbjorklu

8
Nie obsługuje również liczb dziesiętnych, np .: 1.23
littlecodefarmer758

4
@Remy Lebeau, tak. W rzeczywistości nie jest to konwersja ciągu na plik int. Po prostu identyfikuje, czy ciąg składa się z cyfr numerycznych. Nie ma znaczenia, jak długi jest sznurek.
Charles Salvia

5
Nie zapomnij dołączyć <string> <algorithm>i <cctype>sprawić, by przykład C ++ 11 zadziałał.
kR105

89

Po co odkrywać koło na nowo? Biblioteka standardowa C (dostępna również w C ++) ma funkcję, która robi dokładnie to:

char* p;
long converted = strtol(s, &p, 10);
if (*p) {
    // conversion failed because the input wasn't a number
}
else {
    // use converted
}

Jeśli chcesz obsługiwać ułamki lub notację naukową, użyj strtodzamiast tego (otrzymasz doublewynik).

Jeśli chcesz zezwolić na stałe szesnastkowe i ósemkowe w C / C ++ style ( "0xABC"), 0zamiast tego utwórz ostatni parametr .

Twoja funkcja może być zapisana jako

bool isParam(string line)
{
    char* p;
    strtol(line.c_str(), &p, 10);
    return *p == 0;
}

4
Ta funkcja usuwa białe znaki z przodu. W związku z tym musisz sprawdzić pierwszy znak dla isdigit.
chmike,

1
@chmike: Opierając się na moim zrozumieniu pytania, odrzucenie wiodących białych znaków jest poprawnym zachowaniem ( atoiużyte w pytaniu również to robi).
Ben Voigt,

1
Pytanie nie precyzowało tego wprost, ale moje rozumienie wymogu „sprawdza, czy ciąg jest liczbą” oznacza, że ​​cały ciąg jest liczbą, a więc bez spacji. Czułem potrzebę zwrócenia uwagi, że wasza odpowiedź różni się w tym względzie od innych. Twoja odpowiedź może być w porządku, jeśli łańcuch może mieć spacje przed liczbą.
chmike

1
@BenVoigt Mówisz, że pzostanie ustawione, nullptrjeśli strtolsię powiedzie, prawda? To nie to, co widzę :(
Jonathan Mee

2
@JonathanMee: Nie, pbędzie wskazywać na NUL, który kończy ciąg. Więc p != 0i *p == 0.
Ben Voigt

35

W przypadku kompilatora C ++ 11 dla nieujemnych liczb całkowitych użyłbym czegoś takiego (zwróć uwagę na ::zamiast std::):

bool is_number(const std::string &s) {
  return !s.empty() && std::all_of(s.begin(), s.end(), ::isdigit);
}

http://ideone.com/OjVJWh


Jeśli w ciągu znajdują się znaki utf8, pojawi się błąd czasu wykonania.
Król Lew

29

Możesz to zrobić w C ++ za pomocą boost :: lexical_cast. Jeśli naprawdę nalegasz, aby nie używać boostu, możesz po prostu sprawdzić, co robi i to zrobić. To całkiem proste.

try 
{
  double x = boost::lexical_cast<double>(str); // double could be anything with >> operator.
}
catch(...) { oops, not a number }

21
Korzystasz try{} catch{}z dobrego pomysłu? Czy nie powinniśmy tego unikać tak bardzo, jak to tylko możliwe?
Nawaz

32
-1 za nadużycie spróbuj catch ... blogs.msdn.com/b/ericlippert/archive/2008/09/10/…
NoSenseEtAl

14
try {} catch {} jest tutaj odpowiednie. Jednak złapanie (...) to po prostu zła praktyka. W takim przypadku użyj funkcji boost :: bad_lexical_cast jako programu obsługi wyjątków.
NuSkooler,

5
Czuję, że to próba odczytania z pliku. Bez względu na to, ile sprawdzasz pliku, nie będziesz wiedział, czy można go odczytać, dopóki tego nie zrobisz. Albo się uda, albo nie. W takim przypadku będziesz musiał złapać wyjątek. Więc w tym przypadku myślę, że jest to całkiem dobry sposób na zrobienie tego.
Casey

4
@EarlGray - z pewnością chciałbym usłyszeć, jakie działania zależne od systemu operacyjnego mogłyby wykonać okna. Standard jasno określa, jak powinien zachowywać się ten kod.
Edward Strange

16

Chciałem tylko wrzucić ten pomysł, który używa iteracji, ale inny kod robi tę iterację:

#include <string.h>

bool is_number(const std::string& s)
{
    return( strspn( s.c_str(), "-.0123456789" ) == s.size() );
}

Nie jest tak solidna, jak powinna być podczas sprawdzania kropki dziesiętnej lub znaku minus, ponieważ pozwala na istnienie więcej niż jednego z nich i w dowolnej lokalizacji. Dobrą rzeczą jest to, że jest to pojedynczy wiersz kodu i nie wymaga biblioteki innej firmy.

Wyjmij „.” i „-”, jeśli dozwolone są tylko dodatnie liczby całkowite.


błąd: „strspn” nie został zadeklarowany w tym zakresie Myślę, że dzieje się tak, ponieważ brakuje mi „#include”, ale jakiego
Qwertie

4
Jeśli zamierzasz użyć std::string, użyj jego find_first_not_offunkcji członkowskiej.
Ben Voigt,

5
To się nie powiedzie, jeśli przekażesz ciąg „12,3-4,55-”, który oczywiście nie jest prawidłową liczbą
Buzzrick

Buzzrick, w proponowanej odpowiedzi stwierdza się już, że to się nie powiedzie w przypadku wspomnianego numeru innego niż numer.
David Rector

jeśli ograniczysz ją tylko do „0123456789”, formuła jest idealna do testowania liczby całkowitej bez znaku
nie ma nikogo specjalnego

16

Sugerowałbym podejście regex. Pełne dopasowanie wyrażenia regularnego (na przykład przy użyciu boost :: regex ) z

-?[0-9]+([\.][0-9]+)?

pokaże, czy ciąg jest liczbą, czy nie. Obejmuje to liczby dodatnie i ujemne, zarówno całkowite, jak i dziesiętne.

Inne odmiany:

[0-9]+([\.][0-9]+)?

(tylko pozytywne)

-?[0-9]+

(tylko liczba całkowita)

[0-9]+

(tylko dodatnia liczba całkowita)


Ehem, próbowałem użyć std::regexz gcc 4.7, gcc 4.8 - oba rzucają std::regex_errorna dowolny znak [w regexp, nawet dla niewinnego "[abc]" (czy robię to źle?). clang-3.4 w ogóle nie jest tego świadomy <regex>. W każdym razie wydaje się, że to najbardziej rozsądna odpowiedź, +1.
Dmytro Sirenko

3
@EarlGray: Regex jest poprawnie dostępny tylko z GCC 4.9
Lightness Races in Orbit

13

Oto inny sposób na zrobienie tego za pomocą <regex>biblioteki:

bool is_integer(const std::string & s){
    return std::regex_match(s, std::regex("[(-|+)|][0-9]+"));
}

Ach, tak by było. Zaktualizowałem lepsze rozwiązanie. Dzięki.
mpataki14

Czy nie powinno to być „[(- | +) |] [0-9] +” (plus zamiast gwiazdki), w przeciwnym razie Twoje wyrażenie regularne może pasować do „-” lub „+” jako prawidłowej liczby.
David Mulder

Ładny. Nie jestem pewien, co robią (, | i) w tej pierwszej klasie znaków - o ile wiem, te metaznaki tracą swoje specjalne znaczenie wewnątrz klasy postaci. A co z „^ [- +]? [0-9] + $”?
U007D

Może to być nieefektywne. Za każdym razem, gdy jest to wywoływane, wywołuje konstruktor std :: regex, który kompiluje wyrażenie regularne.
user31264

12

Dzięki temu rozwiązaniu możesz sprawdzić wszystko, od liczb ujemnych do dodatnich, a nawet liczb zmiennoprzecinkowych. Gdy zmienisz typ numna liczbę całkowitą, pojawi się błąd, jeśli łańcuch zawiera punkt.

#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;
      }             
}

Udowodnij: program w C ++


10

Uważam, że następujący kod jest najbardziej niezawodny (C ++ 11). Przechwytuje zarówno liczby całkowite, jak i zmiennoprzecinkowe.

#include <regex>
bool isNumber( std::string token )
{
    return std::regex_match( token, std::regex( ( "((\\+|-)?[[:digit:]]+)(\\.(([[:digit:]]+)?))?" ) ) );
}

Wydaje się, że linia using namespace std;jest niepotrzebna.
Xam

6

Spróbuj tego:

isNumber(const std::string &str) {    
  return !str.empty() && str.find_first_not_of("0123456789") == string::npos;
}

1
Ten test dotyczy tylko liczb całkowitych bez znaku
nie ma nikogo specjalnego

5

Oto rozwiązanie sprawdzania dodatnich liczb całkowitych:

bool isPositiveInteger(const std::string& s)
{
    return !s.empty() && 
           (std::count_if(s.begin(), s.end(), std::isdigit) == s.size());
}

4

Brendan to

bool isNumber(string line) 
{
    return (atoi(line.c_str())); 
}

jest prawie w porządku.

zakładając, że każdy ciąg zaczynający się od 0 jest liczbą, po prostu dodaj sprawdzenie dla tego przypadku

bool isNumber(const string &line) 
{
 if (line[0] == '0') return true;
 return (atoi(line.c_str()));
}

ofc "123hello" zwróci prawdę, jak zauważył Tony D.


3

Najprostszy, jaki przychodzi mi do głowy w c ++

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;
}

Przykład kodu roboczego: https://ideone.com/nRX51Y


3

Moje rozwiązanie wykorzystujące C ++ 11 regex ( #include <regex>), może być użyte do dokładniejszego sprawdzenia, na przykład unsigned int, doubleitp:

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);
}

Możesz znaleźć ten kod na http://ideone.com/lyDtfi , można go łatwo zmodyfikować, aby spełniał wymagania.


Poproszę osoby osłabiające, aby pomogły mi zrozumieć problem, poprawię swoją odpowiedź. Dzięki.
aniliitb10


3

Możemy użyć klasy stringstream .

    bool isNumeric(string str)
    {
       stringstream stream;                   
       double number;

       stream<<str;
       stream>>number;

       return stream.eof();
    }

2

Rozwiązanie oparte na komentarzu kbjorklu to:

bool isNumber(const std::string& s)
{
   return !s.empty() && s.find_first_not_of("-.0123456789") == std::string::npos;
}

Podobnie jak w przypadku odpowiedzi Davida Rectora, nie jest ona odporna na ciągi z wieloma kropkami lub znakami minus, ale możesz usunąć te znaki, aby po prostu sprawdzić liczby całkowite.


Jednak jestem zwolennikiem rozwiązania opartego na rozwiązaniu Bena Voigta , używającego strtodw cstdlib do wyszukiwania wartości dziesiętnych, notacji naukowej / inżynierskiej, notacji szesnastkowej (C ++ 11), a nawet INF / INFINITY / NAN (C ++ 11) jest:

bool isNumberC(const std::string& s)
{
    char* p;
    strtod(s.c_str(), &p);
    return *p == 0;
}

2

Korzystanie <regex>. Ten kod został przetestowany!

bool isNumber(const std::string &token)
{
    return std::regex_match(token, std::regex("(\\+|-)?[0-9]*(\\.?([0-9]+))$"));
}

1

Po dokładniejszym zapoznaniu się z dokumentacją, znalazłem odpowiedź, która wspiera moje potrzeby, ale prawdopodobnie nie będzie tak pomocna dla innych. Oto jest (bez irytującego powrotu true i zwrócenia fałszywych stwierdzeń :-))

bool isNumber(string line) 
{
    return (atoi(line.c_str())); 
}

4
Jeśli tak się stanie 0, otrzymasz wynik fałszywie ujemny.
Charles Salvia,

3
To zwróci wszystkie wiodące liczby i nie ostrzeże Cię o końcowych śmieciach (np. „123hello” ==> 123). @Charles: Brendan wspomina, że ​​musi tylko rozpoznać pozytywne intencje w komentarzu do innej odpowiedzi.
Tony Delroy,

1

Myślę, że to wyrażenie regularne powinno obsługiwać prawie wszystkie przypadki

"^(\\-|\\+)?[0-9]*(\\.[0-9]+)?"

więc możesz wypróbować następującą funkcję, która może działać zarówno z (Unicode, jak i ANSI)

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
}

1
include <string>

W przypadku walidacji podwójnych:

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;

}

Do walidacji Ints (z negatywami)

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;

}

Do weryfikacji niepodpisanych stron

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"

}


1
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(); 
}

jak to działa: stringstream >> overload może konwertować łańcuchy do różnych typów arytmetycznych, robi to poprzez sekwencyjne odczytywanie znaków ze strumienia (w tym przypadku ss), dopóki nie zabraknie znaków LUB następny znak nie spełnia kryteriów do zapisania do typu zmiennej docelowej.

Przykład 1:

stringstream ss("11");
double my_number;
ss >> my_number; //my number = 11

przykład2:

stringstream ss("011");
double my_number;
ss >> my_number; //my number = 11

przykład3:

stringstream ss("11ABCD");
double my_number;
ss >> my_number; //my number = 11 (even though there are letters after the 11)

objaśnienie zmiennej „śmieci”:

dlaczego nie po prostu sprawdzić, czy wyodrębnienie do mojego double ma prawidłową wartość, a następnie zwrócić true, jeśli tak?

Zauważ, że przykład3 powyżej nadal pomyślnie odczyta liczbę 11 do zmiennej my_number, nawet jeśli ciąg wejściowy to „11ABCD” (który nie jest liczbą).

aby obsłużyć ten przypadek, możemy wykonać kolejne wyodrębnienie do zmiennej łańcuchowej (którą nazwałem śmieci), która może odczytać wszystko, co mogło zostać w buforze ciągów po początkowym wyodrębnieniu do zmiennej typu double. Jeśli cokolwiek zostanie, zostanie wczytane do „śmieci”, co oznacza, że ​​cały przekazany ciąg nie był liczbą (po prostu zaczyna się od jedynki). w takim przypadku chcielibyśmy zwrócić fałsz;

dołączone „0” wyjaśnienie ”:

próba wyodrębnienia pojedynczego znaku do znaku podwójnego zakończy się niepowodzeniem (zwrócenie 0 do naszego znaku podwójnego), ale nadal spowoduje przesunięcie pozycji bufora ciągu na koniec znaku. W takim przypadku nasz odczyt śmieci będzie pusty, co spowoduje, że funkcja niepoprawnie zwróci wartość true. aby obejść ten problem, dodałem 0 do łańcucha, więc jeśli na przykład przekazany ciąg był „a”, zostanie zmieniony na „0a”, tak że 0 zostanie wyodrębnione do podwójnego, a „a” zostanie wyodrębnione do śmieci.

dodanie 0 nie wpłynie na wartość liczby, więc liczba będzie nadal poprawnie wyodrębniona do naszej podwójnej zmiennej.


1
Chociaż ten kod może odpowiedzieć na pytanie, zapewnia dodatkowy kontekst dotyczący tego, dlaczego i / lub jak ten kod odpowiada, poprawia jego długoterminową wartość.
Ajean

1

aby sprawdzić, czy łańcuch jest liczbą całkowitą, czy zmiennoprzecinkową, możesz użyć:

 #include <sstream>

    bool isNumber(string str) {
    double d;
    istringstream is(str);
    is >> d;
    return !is.fail() && is.eof();
}

1
zwróci to 10 dla ciągu zawierającego wartość „10_is_not_a_number”.
KorreyD

1

Jeszcze inna odpowiedź, która używa stold(choć możesz też użyć stof/ stodjeśli nie potrzebujesz precyzji).

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);
}

1

Spróbuj tego:

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;
}

1

Możesz sprawdzić, czy ciąg można zamienić na liczbę całkowitą, używając boost :: lexical_cast . Jeśli zgłosi wyjątek bad_lexical_cast, to łańcuch nie może zostać przekonwertowany, w przeciwnym razie może.

Zobacz przykład takiego programu testowego poniżej:

#include <boost/lexical_cast.hpp>
#include <iostream>

int main(int, char** argv)
{
        try
        {
                int x = boost::lexical_cast<int>(argv[1]);
                std::cout << x << " YES\n";
        }
        catch (boost::bad_lexical_cast const &)
        {
                std:: cout << "NO\n";
        }
        return 0;
}

Przykładowe wykonanie:

# ./a.out 12
12 YES
# ./a.out 12/3
NO

0

Kilka miesięcy temu zaimplementowałem sposób określania, czy dowolny ciąg jest liczbą całkowitą, szesnastkową czy podwójną.

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;


}

Następnie w swoim programie możesz łatwo przekonwertować liczbę w funkcji na jej typ, jeśli wykonasz następujące czynności,

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;
}

Możesz zdać sobie sprawę, że funkcja zwróci 0, jeśli liczba nie została wykryta. Wartość 0 może być traktowana jako fałszywa (jak wartość logiczna).


0

Proponuję prostą konwencję:

Jeśli konwersja do ASCII jest> 0 lub zaczyna się od 0, to jest to liczba. Nie jest doskonały, ale szybki.

Coś takiego:

string token0;

if (atoi(token0.c_str())>0 || isdigit(token0.c_str()[0]) ) { //this is a value
    // do what you need to do...
}

0

Ta funkcja zajmuje się wszystkimi możliwymi przypadkami:

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....
}

0

Czy możesz po prostu użyć kodu powrotu sscanf, aby określić, czy jest to int?

bool is_number(const std::string& s)
{
    int value;
    int result = sscanf(valueStr.c_str(), "%d", &value);
    return (result != EOF && readResult != 0);
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.