Как определить, является ли строка числом с С++?
У меня было довольно много проблем с попыткой написать функцию, которая проверяет, является ли строка числом. Для игры, которую я пишу, мне просто нужно проверить, является ли строка из файла, который я читаю, числом или нет (я буду знать, является ли это параметром таким образом). Я написал функцию ниже, которая, как я считаю, работает плавно (или я случайно отредактировал ее, чтобы остановить ее, или я шизофреник или Windows шизофреник):
bool isParam (string line)
{
if (isdigit(atoi(line.c_str())))
return true;
return false;
}
Ответы
Ответ 1
Самый эффективный способ - просто перебрать строку, пока не найдете символ без цифр. Если есть несимметричные символы, вы можете считать строку не числом.
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();
}
Или если вы хотите сделать это способом С++ 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();
}
Как указано в комментариях ниже, это работает только для целых положительных чисел. Если вам нужно обнаружить отрицательные целые числа или фракции, вы должны пойти с более надежным решением на базе библиотеки. Хотя добавление поддержки отрицательных целых чисел довольно тривиально.
Ответ 2
Зачем изобретать колесо? Стандартная библиотека 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/С++ ("0xABC"
), тогда вместо этого сделайте последний параметр 0
.
Затем ваша функция может быть записана как
bool isParam(string line)
{
char* p;
strtol(line.c_str(), &p, 10);
return *p == 0;
}
Ответ 3
Вы можете сделать это с помощью С++ с boost:: lexical_cast. Если вы действительно настаиваете на том, чтобы не использовать boost, вы можете просто изучить, что он делает, и сделать это. Это довольно просто.
try
{
double x = boost::lexical_cast<double>(str); // double could be anything with >> operator.
}
catch(...) { oops, not a number }
Ответ 4
С компилятором С++ 11 для неотрицательных целых чисел я бы использовал что-то вроде этого (обратите внимание на ::
вместо std::
):
bool is_number(const std::string &s) {
return !s.empty() && std::all_of(s.begin(), s.end(), ::isdigit);
}
http://ideone.com/OjVJWh
Ответ 5
Я бы предложил подход с регулярным выражением. Полное регулярное выражение (например, используя boost:: regex) с помощью
-?[0-9]+([.][0-9]+)?
будет показывать, является ли строка числом или нет. Это включает в себя положительные и отрицательные числа, как целое, так и десятичное.
Другие варианты:
[0-9]+([.][0-9]+)?
(только положительный)
-?[0-9]+
(только целое число)
[0-9]+
(только положительное целое число)
Ответ 6
Я просто хотел использовать эту идею, которая использует итерацию, но какой-то другой код выполняет эту итерацию:
#include <string.h>
bool is_number(const std::string& s)
{
return( strspn( s.c_str(), "-.0123456789" ) == s.size() );
}
Он не устойчив, как это должно быть при проверке знака десятичной точки или минуса, поскольку он позволяет иметь более одного из каждого и в любом месте. Хорошо, что это единственная строка кода и не требует сторонней библиотеки.
Выньте '.' и '-', если допустимы целые положительные числа.
Ответ 7
С помощью этого решения вы можете проверить все: от отрицательных до положительных чисел и даже числа с плавающей запятой. Когда вы меняете тип num
на integer, вы получите сообщение об ошибке, если строка содержит точку.
#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;
}
}
Докажите: Программа на С++
Ответ 8
Здесь другой способ сделать это с помощью библиотеки <regex>
:
bool is_integer(const std::string & s){
return std::regex_match(s, std::regex("[(-|+)|][0-9]+"));
}
Ответ 9
Я нашел следующий код, чтобы быть наиболее надежным (c ++ 11). Ловит целые числа и числа с плавающей точкой.
#include <regex>
bool isNumber( std::string token )
{
return std::regex_match( token, std::regex( ( "((\\+|-)?[[:digit:]]+)(\\.(([[:digit:]]+)?))?" ) ) );
}
Ответ 10
Вот решение для проверки положительных целых чисел:
bool isPositiveInteger(const std::string& s)
{
return !s.empty() &&
(std::count_if(s.begin(), s.end(), std::isdigit) == s.size());
}
Ответ 11
Попробуйте следующее:
isNumber(const std::string &str) {
return !str.empty() && str.find_first_not_of("0123456789") == string::npos;
}
Ответ 12
Брендан это
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" вернется, как заметил Тони Д.
Ответ 13
Простейший, о котором я могу думать в С++
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
Ответ 14
Решение на основе комментария kbjorklu:
bool isNumber(const std::string& s)
{
return !s.empty() && s.find_first_not_of("-.0123456789") == std::string::npos;
}
Как и в случае с ответом Дэвида Ректора, он не устойчив к строкам с несколькими точками или минус-знаками, но вы можете удалить эти символы, чтобы просто проверить целые числа.
Однако я частично согласен с решением, основанным на решении Ben Voigt, используя strtod
в cstdlib, чтобы посмотреть десятичные значения, научную/инженерную нотацию, шестнадцатеричную нотацию (С++ 11) или даже INF/INFINITY/NAN (С++ 11):
bool isNumberC(const std::string& s)
{
char* p;
strtod(s.c_str(), &p);
return *p == 0;
}
Ответ 15
Мое решение с использованием регулярного выражения С++ 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, это можно легко изменить, чтобы соответствовать требованиям.
Ответ 16
Мы можем использовать класс stringstream.
bool isNumeric(string str)
{
stringstream stream;
double number;
stream<<str;
stream>>number;
return stream.eof();
}
Ответ 17
Использование <regex>
. Этот код был протестирован!
bool isNumber(const std::string &token)
{
return std::regex_match(token, std::regex("(\\+|-)?[0-9]*(\\.?([0-9]+))$"));
}
Ответ 18
После консультации с документацией немного больше, я придумал ответ, который поддерживает мои потребности, но, вероятно, не будет таким же полезным для других. Вот он (без раздражающего возвращения true и возвращает ложные утверждения:-))
bool isNumber(string line)
{
return (atoi(line.c_str()));
}
Ответ 19
Я думаю, что это регулярное выражение должно обрабатывать почти все случаи
"^(\\-|\\+)?[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
}
Ответ 20
чтобы проверить, является ли строка целым числом или с плавающей запятой или вы можете использовать:
#include <sstream>
bool isNumber(string str) {
double d;
istringstream is(str);
is >> d;
return !is.fail() && is.eof();
}
Ответ 21
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"
}
Ответ 22
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();
}
как это работает:
stringload → overload может преобразовывать строки в различные типы арифметических операций
он делает это, читая символы последовательно из строкового потока (ss в этом случае), пока не закончится символ ИЛИ следующий символ не будет соответствовать критериям, которые будут сохранены в тип переменной назначения.
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)
объяснение переменной "мусор":
Почему бы просто не проверить, имеет ли значение извлечения в моем двойном значение действительное значение, а затем возвращает true, если оно есть?
Обратите внимание, что пример3 выше все еще успешно прочитает номер 11 в переменной my_number, даже если входная строка "11ABCD" (которая не является числом).
для обработки этого случая мы можем сделать другое извлечение в строковой переменной (которую я назвал мусором), которая может читать все, что могло быть оставлено в буфере строк после первоначального извлечения в переменную типа double. Если что-то осталось, он будет считаться "мусором", что означает, что полная строка, прошедшая мимо, не была числом (она начинается только с одного). в этом случае мы хотели бы вернуть false;
добавленное "0" объяснение ":
попытка извлечь один символ в двойник не сработает (возврат 0 в наш double), но все равно будет перемещать позицию буфера строки после символа. В этом случае наше чтение мусора будет пустым, что приведет к неправильной ошибке функции true.
чтобы обойти это, я добавил 0 к строке, чтобы, если, например, строка, переданная в "a", она была изменена на "0a", так что 0 будет извлечен в double, а "a" будет извлечен в мусор.
добавление 0 не повлияет на значение числа, поэтому число будет по-прежнему правильно извлечено в нашу двойную переменную.
Ответ 23
Как мне было показано в ответе на мой родственный вопрос, я чувствую, что вы должны использовать повышение:: преобразование:: try_lexical_convert
Ответ 24
Несколько месяцев назад я применил способ определения, является ли любая строка целым, шестнадцатеричным или двойным.
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 можно рассматривать как false (например, boolean).
Ответ 25
Я предлагаю простое соглашение:
Если преобразование в 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...
}
Ответ 26
Еще один ответ, который использует 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);
}
Ответ 27
Эта функция выполняет все возможные случаи:
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....
}
Ответ 28
Не могли бы вы просто использовать код возврата sscanf, чтобы определить, является ли это int?
bool is_number(const std::string& s)
{
int value;
int result = sscanf(valueStr.c_str(), "%d", &value);
return (result != EOF && readResult != 0);
}
Ответ 29
Попробуй это:
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;
}
Ответ 30
С /C++ стиль для целых чисел без знака, используя диапазон на основе for
C++ 11:
int isdigits(const std::string & s)
{
for (char c : s) if (!isdigit(c)) return (0);
return (1);
}