it-roy-ru.com

Как определить, является ли строка числом с C++?

У меня было немало проблем, когда я пытался написать функцию, которая проверяет, является ли строка числом. Для игры, которую я пишу, мне просто нужно проверить, является ли строка из файла, который я читаю, числом или нет (я буду знать, является ли это параметром таким образом). Я написал нижеприведенную функцию, которая, по моему мнению, работала гладко (или я случайно отредактировал ее, чтобы остановить, или я шизофреник, или Windows шизофреник):

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

    return false;
}
98
Brendan Weinstein

Самый эффективный способ - просто перебирать строку, пока не найдете нецифровый символ. Если есть какие-либо нецифровые символы, вы можете считать строку не числом.

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

Или, если вы хотите сделать это на C++ 11:

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

Как указано в комментариях ниже, это работает только для натуральных чисел. Если вам нужно обнаружить отрицательные целые или дробные числа, вам следует использовать более надежное решение на основе библиотеки. Хотя добавление поддержки отрицательных целых чисел довольно тривиально.

110
Charles Salvia

Зачем изобретать велосипед? Стандартная библиотека C (также доступна на C++) имеет функцию, которая делает именно это:

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

Если вы хотите обрабатывать дроби или научные записи, используйте вместо этого strtod (вы получите результат double).

Если вы хотите разрешить шестнадцатеричные и восьмеричные константы в стиле C/C++ ("0xABC"), вместо этого укажите последний параметр 0.

Ваша функция тогда может быть записана как

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

Вы можете сделать это в C++ с помощью boost :: lexical_cast. Если вы действительно настаиваете на том, чтобы не использовать повышение, вы можете просто изучить, что он делает, и сделать это. Это довольно просто.

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

С компилятором C++ 11 для неотрицательных целых чисел я бы использовал что-то вроде этого (обратите внимание на :: вместо std::):

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

http://ideone.com/OjVJWh

16
szx

Я просто хотел добавить эту идею, которая использует итерацию, но какой-то другой код выполняет эту итерацию:

#include <string.h>

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

Он не является надежным, как должно быть при проверке десятичной точки или знака минус, поскольку он позволяет использовать более одного знака в любом месте. Хорошо то, что это одна строка кода и не требует сторонней библиотеки.

Выньте «.» и '-', если разрешены целые положительные числа.

13
David Rector

С этим решением вы можете проверить все, от отрицательных до положительных чисел и даже числа с плавающей запятой. Когда вы меняете тип num на целое число, вы получите ошибку, если строка содержит точку.

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

Докажите: Программа C++

12
tom1991te

Я бы предложил подход регулярных выражений. Полное соответствие регулярному выражению (например, использование boost :: regex ) с 

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

покажет, является ли строка числом или нет. Это включает в себя положительные и отрицательные числа, целые, а также десятичные.

Другие варианты:

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

(только позитив)

-?[0-9]+

(только целое число)

[0-9]+

(только положительное целое число)

11
Mephane

Вот еще один способ сделать это с помощью библиотеки <regex>:

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

Я нашел следующий код, чтобы быть наиболее надежным (c ++ 11). Ловит целые числа и числа с плавающей точкой. 

bool isNumber( std::string token )
{
    using namespace std;
    return std::regex_match( token, std::regex( ( "((\\+|-)?[[:digit:]]+)(\\.(([[:digit:]]+)?))?" ) ) );
}
4
dk123

Попробуй это:

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

Брендан это

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

почти нормально.

предполагая, что любая строка, начинающаяся с 0, является числом, Просто добавьте проверку для этого случая

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

ofc "123hello" вернет true, как заметил Тони Д.

2
Noam Geffen

Вот решение для проверки положительных целых чисел:

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

Самое простое, что я могу придумать в 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;
}

Пример рабочего кода: https://ideone.com/nRX51Y

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

как это работает: Перегрузка stringstream >> может преобразовывать строки в различные арифметические типыit делает это путем последовательного чтения символов из потока строк (в данном случае ss), пока в нем не заканчиваются символы OR следующий символ не соответствует критериям для сохранения в тип переменной назначения.

example1:

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

example2:

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

example3:

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

объяснение переменной «мусор»:

почему бы просто не проверить, есть ли у извлечения в моем double правильное значение, а затем вернуть true, если оно есть?

обратите внимание, что в приведенном выше примере 3 все еще будет успешно считано число 11 в переменную my_number, даже если входная строка - «11ABCD» (которая не является числом).

чтобы справиться с этим случаем, мы можем выполнить другое извлечение в строковую переменную (которую я назвал мусором), которая может прочитать все, что могло остаться в строковом буфере после первоначального извлечения в переменную типа double. Если что-то осталось, оно будет считано «мусором», что означает, что переданная полная строка не была числом (она просто начинается с единицы). в этом случае мы бы хотели вернуть false;

предварительное объяснение "0":

попытка извлечь единственный символ в двойник потерпит неудачу (вернет 0 в наш двойник), но все равно переместит позицию строкового буфера после символа. В этом случае наше чтение мусора будет пустым, что заставит функцию неправильно возвращать true ., Чтобы обойти это, я добавил к строке 0, так что если, например, переданная строка была "a", она была изменена на «0a», так что 0 будет извлечено в двойник, а «a» извлечено в мусор. 

добавление 0 не повлияет на значение числа, поэтому число все равно будет правильно извлечено в нашу двойную переменную.

1
KorreyD

Как мне было показано в ответе на мой связанный вопрос, я чувствую, что вы должны использовать boost :: Conversion :: try_lexical_convert

1
NoSenseEtAl

Решение, основанное на комментарий от kbjorklu это:

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

Как и в случае с ответом Дэвида Ректора он не подходит для строк с несколькими точками или знаками минус, но вы можете удалить эти символы, чтобы просто проверить на целые числа.


Тем не менее, я неравнодушен к решению, основанному на решении Бена Фойгта , использующем strtod в cstdlib для просмотра десятичных значений, научной/инженерной записи, шестнадцатеричной записи (C++ 11) или даже INF/INFINITY/NAN ( C++ 11) это:

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

чтобы проверить, является ли строка целым числом или числом с плавающей запятой, вы можете использовать:

 #include <sstream>

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

Я думаю, что это регулярное выражение должно обрабатывать почти все случаи

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

так что вы можете попробовать следующую функцию, которая может работать как с Unicode, так и с 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
Motaz
include <string>

Для проверки двойников:

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;

}

Для проверки значений (с отрицательными значениями)

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;

}

Для проверки неподписанных целых

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
Erik Nordin

После более подробного изучения документации я нашел ответ, который отвечает моим потребностям, но, вероятно, не будет таким полезным для других. Вот оно (без надоедливого возврата true и возврата false :-))

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

Мы можем использовать stringstream class. 

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

       stream<<str;
       stream>>number;

       return stream.eof();
    }
0
rashedcs

Мое решение, использующее регулярное выражение C++ 11 (#include <regex>), может использоваться для более точной проверки, например unsigned int, double и т. Д .:

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

Вы можете найти этот код по адресу http://ideone.com/lyDtfi , его можно легко изменить в соответствии с требованиями.

0
aniliitb10

Эта функция заботится обо всех возможных случаях:

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
Vaibhav Gupta

Несколько месяцев назад я реализовал способ определения, является ли любая строка целочисленной, шестнадцатеричной или двойной.

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;


}

Тогда в вашей программе вы можете легко преобразовать число в функцию его типа, если вы выполните следующее,

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

Вы можете понять, что функция вернет 0, если число не было обнаружено. 0 это может рассматриваться как ложное (как логическое).

0
Jordi Espada

Я предлагаю простое соглашение:

Если преобразование в ASCII равно> 0 или начинается с 0, то это число. Это не идеально, но быстро.

Что-то вроде этого:

string token0;

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

Использование <regex>. Этот код был протестирован!

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

Попробуй это:

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

Еще один ответ, который использует stold (хотя вы также можете использовать stof/stod, если вам не требуется точность).

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);
}
0
Tim Angus

Не могли бы вы просто использовать код возврата sscanf, чтобы определить, является ли это int?

bool is_number(const std::string& s)
{
    int value;
    int result = sscanf(valueStr.c_str(), "%d", &value);
    return (result != EOF && readResult != 0);
}
0
David D