Làm thế nào để xác định nếu một chuỗi là một số với C ++?


136

Tôi đã gặp khá nhiều rắc rối khi cố gắng viết một hàm kiểm tra xem một chuỗi có phải là một số không. Đối với một trò chơi tôi đang viết tôi chỉ cần kiểm tra xem một dòng trong tệp tôi đang đọc có phải là số hay không (tôi sẽ biết nếu đó là một tham số theo cách này). Tôi đã viết chức năng dưới đây mà tôi tin là đã hoạt động trơn tru (hoặc tôi vô tình chỉnh sửa để ngăn chặn nó hoặc tôi bị tâm thần phân liệt hoặc Windows là tâm thần phân liệt):

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

    return false;
}

184
Tôi ghét nhìn thấy if (expr) return true; return false;! Chỉ cần viết return expr;.
ephemient

17
@ephemient Phong cách của tôi là làm giống như bạn. Nhưng nó thực sự là một vấn đề lớn?
Brennan Vincent

2
Nguyên mẫu chức năng của bạn có vẻ không phù hợp. Tại sao không sử dụng bool isParam (chuỗi const & line)
MikimotoH

4
Vâng. Tôi có một thói quen xấu là viết mã kiểu dài khi học một ngôn ngữ mới. Tôi chưa quen với C ++ và do dự hơn về "phím tắt" (hoặc các phím tắt nhận thức).
Brendan Weinstein

57
@Brennan Vincent: Vâng, đó là một vấn đề lớn. Đó là cùng một loại sai lầm như if (expr) return expr; else return expr;, if (expr == true), (if expr != false), hoặc if ((expr == true) == true). Tất cả đều giới thiệu sự phức tạp không có lợi cho người viết, người đọc hoặc trình biên dịch mã. Việc loại bỏ sự phức tạp không cần thiết không phải là một lối tắt; đó là chìa khóa để viết phần mềm tốt hơn.
MSalters

Câu trả lời:


148

Cách hiệu quả nhất sẽ chỉ là lặp qua chuỗi cho đến khi bạn tìm thấy một ký tự không có chữ số. Nếu có bất kỳ ký tự không có chữ số nào, bạn có thể coi chuỗi không phải là số.

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

Hoặc nếu bạn muốn làm theo cách C ++ 11:

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

Như đã chỉ ra trong các ý kiến ​​dưới đây, điều này chỉ hoạt động cho các số nguyên dương. Nếu bạn cần phát hiện các số nguyên hoặc phân số âm, bạn nên đi với một giải pháp dựa trên thư viện mạnh mẽ hơn. Mặc dù, việc thêm hỗ trợ cho các số nguyên âm là khá nhỏ.


6
Cũng không xử lý số âm và số không toàn bộ. Chúng tôi không thể biết những yêu cầu dựa trên câu hỏi.
Brennan Vincent

76
Bạn cũng có thể sử dụng !s.empty() && s.find_first_not_of("0123456789") == std::string::npos;cho một lớp lót C ++ 03.
kbjorklu

8
Cũng không xử lý các số thập phân, ví dụ: 1.23
littlecodefarmer758

3
@Remy Lebeau, đúng vậy. Nó không thực sự chuyển đổi chuỗi thành một int. Nó chỉ xác định xem một chuỗi có bao gồm các chữ số hay không. Nó không quan trọng chuỗi dài bao nhiêu.
Charles Salvia

5
Đừng quên bao gồm <string> <algorithm><cctype>để làm cho ví dụ C ++ 11 hoạt động.
kR105

88

Tại sao phải phát minh lại bánh xe? Thư viện chuẩn C (cũng có sẵn trong C ++) có chức năng thực hiện chính xác điều này:

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

Nếu bạn muốn xử lý phân số hoặc ký hiệu khoa học, strtodthay vào đó, bạn sẽ nhận được doublekết quả).

Nếu bạn muốn cho phép các hằng thập lục phân và bát phân theo kiểu C / C ++ ( "0xABC"), thì hãy tạo tham số cuối cùng 0để thay thế.

Chức năng của bạn sau đó có thể được viết là

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

4
Chức năng này loại bỏ khoảng trắng phía trước. Do đó, bạn phải kiểm tra char đầu tiên cho isdigit.
chmike

1
@chmike: Dựa trên sự hiểu biết của tôi về câu hỏi, loại bỏ khoảng trắng hàng đầu là hành vi đúng ( atoinhư được sử dụng trong câu hỏi cũng làm điều này).
Ben Voigt

1
Câu hỏi không chỉ định rõ ràng, nhưng sự hiểu biết của tôi về yêu cầu "kiểm tra xem một chuỗi có phải là số không" có nghĩa là toàn bộ chuỗi là số, do đó không có khoảng trắng. Tôi cảm thấy cần phải chỉ ra rằng câu trả lời của bạn khác với những người khác về vấn đề này. Câu trả lời của bạn có thể ổn nếu chuỗi đó có khoảng trắng ở trước số.
chmike

1
@BenVoigt Bạn đang nói rằng psẽ được đặt thành nullptrnếu strtolthành công, phải không? Đó không phải là những gì tôi đang thấy :(
Jonathan Mee

2
@JonathanMee: Không, psẽ được trỏ đến NUL chấm dứt chuỗi. Vì vậy p != 0*p == 0.
Ben Voigt

33

Với trình biên dịch C ++ 11, đối với các số nguyên không âm tôi sẽ sử dụng một cái gì đó như thế này (lưu ý ::thay vì std::):

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

http://ideone.com/OjVJWh


1
Đây là câu trả lời tốt nhất.
Martin Broadhurst

Nếu có các ký tự utf8 trong chuỗi, bạn sẽ gặp lỗi thời gian chạy.
Vua sư tử

29

Bạn có thể làm theo cách C ++ với boost :: lexical_cast. Nếu bạn thực sự khăng khăng không sử dụng boost, bạn có thể kiểm tra xem nó làm gì và làm điều đó. Nó khá đơn giản.

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

21
Sử dụng try{} catch{}một ý tưởng tốt? Chúng ta không nên tránh nó càng nhiều càng tốt?
Nawaz

32
-1 cho lạm dụng cố gắng nắm bắt ... blogs.msdn.com/b/ericlippert/archive/2008/09/10/...
NoSenseEtAl

14
thử {} bắt {} là thích hợp ở đây. Tuy nhiên, bắt (...) chỉ là thực hành xấu. Trong trường hợp này, sử dụng boost :: bad_lexical_cast cho trình xử lý ngoại lệ của bạn.
NuSkooler

5
Tôi cảm thấy như điều này đang cố đọc từ một tập tin. Cho dù bạn có kiểm tra bao nhiêu trên tệp bạn cũng không biết liệu có thể đọc được từ đó cho đến khi bạn thực hiện được không. Nó sẽ đi làm hoặc không. Trong trường hợp bạn sẽ cần phải bắt một ngoại lệ. Vì vậy, trong trường hợp này tôi nghĩ rằng đây là một cách hoàn toàn tốt để làm điều đó.
Casey

4
@EarlGray - Tôi chắc chắn sẽ thích thú khi nghe những gì cửa sổ hành động phụ thuộc hệ điều hành sẽ làm. Tiêu chuẩn khá rõ ràng về cách hành xử của mã này.
Edward Strange

16

Tôi chỉ muốn đưa ra ý tưởng này sử dụng phép lặp nhưng một số mã khác thực hiện phép lặp đó:

#include <string.h>

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

Nó không mạnh mẽ như khi kiểm tra dấu thập phân hoặc dấu trừ vì nó cho phép có nhiều hơn một và ở bất kỳ vị trí nào. Điều tốt là nó là một dòng mã duy nhất và không yêu cầu thư viện của bên thứ ba.

Hãy lấy ra '.' và '-' nếu số nguyên dương là tất cả những gì được phép.


lỗi: 'strspn' không được khai báo trong phạm vi này Tôi nghĩ rằng điều này là do tôi đang thiếu "#include" nhưng là gì
Qwertie

4
Nếu bạn sẽ sử dụng std::string, sử dụng find_first_not_ofchức năng thành viên của nó .
Ben Voigt

5
Điều này sẽ thất bại nếu bạn vượt qua một chuỗi "12.3-4.55-", đây rõ ràng không phải là một số hợp lệ
Buzzrick

Buzzrick, câu trả lời được đề xuất đã nói rằng điều này sẽ thất bại với số không bạn đã đề cập.
David Hiệu trưởng

nếu bạn giới hạn chỉ ở mức "0123456789" thì công thức hoàn hảo để kiểm tra số nguyên không dấu
không ai đặc biệt

16

Tôi muốn đề xuất một cách tiếp cận regex. Kết hợp regex đầy đủ (ví dụ: sử dụng boost :: regex ) với

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

sẽ hiển thị cho dù chuỗi là một số hay không. Điều này bao gồm số dương và số âm, số nguyên cũng như số thập phân.

Các biến thể khác:

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

(chỉ tích cực)

-?[0-9]+

(chỉ số nguyên)

[0-9]+

(chỉ số nguyên dương)


Ahem, tôi đã thử sử dụng std::regexvới gcc 4.7, gcc 4.8 - cả hai đều đưa std::regex_errorra bất kỳ dấu hiệu nào [trong regrec, ngay cả đối với một "[abc]" vô tội (tôi có làm sai không?). vang-3.4 là không nhận thức được <regex>gì cả. Dù sao, đây dường như là câu trả lời rõ ràng nhất, +1.
Dmytro Sirenko

3
@EarlGray: Regex chỉ khả dụng đúng cách từ GCC 4.9
Các cuộc đua nhẹ nhàng trong quỹ đạo

13

Đây là một cách khác để làm điều đó bằng <regex>thư viện:

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

Ah, vậy nó sẽ Tôi đã cập nhật với một giải pháp tốt hơn. Cảm ơn.
mpataki14

Không nên là "[(- | +) |] [0-9] +" (cộng thay vì dấu sao), nếu không regex của bạn có thể khớp với "-" hoặc "+" là số hợp lệ.
David Mulder

Đẹp. Tôi không chắc những gì (, | và) đang làm trong lớp nhân vật đầu tiên đó - những nhân vật siêu nhân đó mất đi ý nghĩa đặc biệt của họ trong một lớp nhân vật theo như tôi biết. Làm thế nào về "^ [- +]? [0-9] + $"?
U007D

Nó có thể không hiệu quả. Mỗi lần được gọi, nó gọi hàm tạo std :: regex sẽ biên dịch biểu thức chính quy.
user31264

12

Với giải pháp này, bạn có thể kiểm tra mọi thứ từ số âm đến số dương và thậm chí cả số float. Khi bạn thay đổi loại numthành số nguyên, bạn sẽ gặp lỗi nếu chuỗi chứa một điểm.

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

Chứng minh: Chương trình C ++


10

Tôi đã tìm thấy đoạn mã sau là mạnh nhất (c ++ 11). Nó bắt cả số nguyên và số float.

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

Có vẻ như dòng using namespace std;này là không cần thiết.
Xam

5

Đây là một giải pháp để kiểm tra các số nguyên dương:

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

5

Thử cái này:

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

1
Thử nghiệm này chỉ dành cho số nguyên không dấu
không ai đặc biệt

4

Brendan này

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

gần như ok

giả sử bất kỳ chuỗi nào bắt đầu bằng 0 là một số, chỉ cần thêm một kiểm tra cho trường hợp này

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

ofc "123hello" sẽ trở lại đúng như Tony D đã lưu ý.


3

Đơn giản nhất tôi có thể nghĩ về 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;
}

Mẫu mã làm việc: https://ideone.com/nRX51Y


3

Giải pháp của tôi sử dụng C ++ 11 regex ( #include <regex>), nó có thể được sử dụng để kiểm tra chính xác hơn, như unsigned int, doublev.v .:

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

Bạn có thể tìm thấy mã này tại http://ideone.com/lyDtfi , điều này có thể dễ dàng sửa đổi để đáp ứng các yêu cầu.


Tôi yêu cầu downvoters giúp tôi hiểu vấn đề, tôi sẽ cải thiện câu trả lời của mình. Cảm ơn.
aniliitb10

2

Một giải pháp dựa trên nhận xét của kbjorklu là:

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

Như với câu trả lời của David Rector, nó không mạnh đối với các chuỗi có nhiều dấu chấm hoặc dấu trừ, nhưng bạn có thể xóa các ký tự đó để chỉ kiểm tra các số nguyên.


Tuy nhiên, tôi là một phần của một giải pháp, dựa trên giải pháp của Ben Voigt , sử dụng strtodtrong cstdlib để xem các giá trị thập phân, ký hiệu khoa học / kỹ thuật, ký hiệu thập lục phân (C ++ 11) hoặc thậm chí INF / INFINITY / NAN (C ++ 11) Là:

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

2

Chúng tôi có thể sử dụng một stringstream lớp.

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

       stream<<str;
       stream>>number;

       return stream.eof();
    }

2

Sử dụng <regex>. Mã này đã được thử nghiệm!

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

1

Sau khi tham khảo tài liệu nhiều hơn một chút, tôi đã đưa ra một câu trả lời hỗ trợ nhu cầu của mình, nhưng có lẽ sẽ không hữu ích cho người khác. Đây là (không có trả lại khó chịu đúng và trả về các tuyên bố sai :-))

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

4
Nếu con số xảy ra 0, bạn sẽ nhận được âm tính giả.
Charles Salvia

3
Điều này sẽ trả về bất kỳ số hàng đầu nào và không cảnh báo bạn về rác thải (ví dụ: "123hello" ==> 123). @Charles: Brendan đề cập rằng anh ta chỉ cần nhận ra ints tích cực trong một bình luận về một câu trả lời khác.
Tony Delroy

1

Tôi nghĩ rằng biểu thức thường xuyên này sẽ xử lý hầu hết các trường hợp

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

để bạn có thể thử chức năng sau có thể hoạt động với cả hai (Unicode và 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>

Để xác thực nhân đôi:

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;

}

Để xác thực Ints (Có phủ định)

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;

}

Để xác thực Ints chưa ký

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

làm thế nào nó hoạt động: chuỗi dòng >> quá tải có thể chuyển đổi chuỗi thành các loại số học khác nhau bằng cách đọc các ký tự liên tục từ chuỗi (ss trong trường hợp này) cho đến khi hết ký tự HOẶC ký tự tiếp theo không đáp ứng tiêu chí được lưu trữ vào loại biến đích.

ví dụ 1:

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

ví dụ2:

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

ví dụ 3:

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

giải thích biến "rác":

Tại sao không kiểm tra xem trích xuất vào đôi của tôi có giá trị hợp lệ không và sau đó trả về true nếu có?

chú ý example3 ở trên vẫn sẽ đọc thành công số 11 vào biến my_number ngay cả khi chuỗi đầu vào là "11ABCD" (không phải là số).

để xử lý trường hợp này, chúng ta có thể thực hiện một trích xuất khác thành một biến chuỗi (mà tôi đặt tên là rác) có thể đọc bất cứ thứ gì có thể còn sót lại trong bộ đệm chuỗi sau khi trích xuất ban đầu thành biến kiểu kép. Nếu bất cứ thứ gì còn sót lại, nó sẽ được đọc thành "rác", có nghĩa là toàn bộ chuỗi được truyền vào không phải là một số (nó chỉ bắt đầu bằng một). trong trường hợp này chúng tôi muốn trả về false;

phần giải thích "0" được thêm vào:

cố gắng trích xuất một ký tự thành một nhân đôi sẽ thất bại (trả về 0 thành gấp đôi của chúng ta) nhưng vẫn sẽ di chuyển vị trí bộ đệm chuỗi sang sau ký tự. Trong trường hợp này, phần đọc rác của chúng ta sẽ trống, điều này sẽ khiến hàm trả về không đúng. để giải quyết vấn đề này, tôi đã thêm 0 vào chuỗi để nếu ví dụ chuỗi được truyền vào là "a" thì nó được đổi thành "0a" để 0 sẽ được trích xuất thành gấp đôi và "a" được trích xuất thành rác.

nhập trước 0 sẽ không ảnh hưởng đến giá trị của số nên số vẫn sẽ được trích xuất chính xác vào biến kép của chúng tôi.


1
Mặc dù mã này có thể trả lời câu hỏi, cung cấp ngữ cảnh bổ sung về lý do và / hoặc cách mã này trả lời câu hỏi cải thiện giá trị lâu dài của nó.
Ajean

1

để kiểm tra xem một chuỗi là số nguyên hay dấu phẩy động hay không, do đó bạn có thể sử dụng:

 #include <sstream>

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

1
cái này sẽ trả về 10 cho một chuỗi chứa giá trị "10_is_not_a_number".
KorreyD

1

Một câu trả lời khác, đó là sử dụng stold(mặc dù bạn cũng có thể sử dụng stof/ stodnếu bạn không yêu cầu độ chính xác).

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

Thử cái này:

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

Bạn có thể kiểm tra xem một chuỗi có thể chuyển đổi thành số nguyên hay không bằng cách sử dụng boost :: lexical_cast . Nếu nó ném ngoại lệ bad_lexical_cast thì chuỗi không thể được chuyển đổi, nếu không nó có thể.

Xem ví dụ về chương trình thử nghiệm như vậy dưới đây:

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

Thực hiện mẫu:

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

0

Vài tháng trước, tôi đã thực hiện một cách để xác định xem bất kỳ chuỗi nào là số nguyên, thập lục phân hay gấp đôi.

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;


}

Sau đó, trong chương trình của bạn, bạn có thể dễ dàng chuyển đổi số trong chức năng loại của nó nếu bạn làm như sau,

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

Bạn có thể nhận ra rằng hàm sẽ trả về 0 nếu số không được phát hiện. Số 0 nó có thể được coi là sai (như boolean).


0

Tôi đề xuất một quy ước đơn giản:

Nếu chuyển đổi sang ASCII> 0 hoặc bắt đầu bằng 0 thì đó là một số. Nó không hoàn hảo nhưng nhanh chóng.

Một cái gì đó như thế này:

string token0;

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

0

Hàm này xử lý tất cả các trường hợp có thể:

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

Bạn có thể chỉ cần sử dụng mã trả về của sscanf để xác định xem đó có phải là int không?

bool is_number(const std::string& s)
{
    int value;
    int result = sscanf(valueStr.c_str(), "%d", &value);
    return (result != EOF && readResult != 0);
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.