文字列がC ++の数値であるかどうかを判断する方法は?


136

文字列が数値であるかどうかをチェックする関数を作成するのにかなり苦労しました。私が書いているゲームの場合は、読み取っているファイルの行が数値であるかどうかを確認するだけです(この方法でパラメーターかどうかがわかります)。私はスムーズに機能していると思われる以下の関数を作成しました(または誤って編集して停止したか、統合失調症であるか、Windowsが統合失調症です)。

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

    return false;
}

184
私は嫌い見てif (expr) return true; return false;!書くだけreturn expr;

17
@ephemient私のスタイルはあなたと同じことです。しかし、それは本当に大きな問題なのでしょうか?
ブレナンヴィンセント

2
関数のプロトタイプが適切ではないようです。bool isParam(const string&line)を使用しない理由
MikimotoH

4
うん。新しい言語を学ぶとき、長いスタイルでコーディングするという悪い癖があります。私はC ++の初心者であり、「ショートカット」(または認識されているショートカット)には抵抗があります。
Brendan Weinstein

57
@ブレナン・ヴィンセント:はい、大したことです。これは、ミスなどの同じクラスだif (expr) return expr; else return expr;if (expr == true)(if expr != false)、またはif ((expr == true) == true)。それらはすべて、コードのライター、リーダー、またはコンパイラーに利益をもたらさない複雑さをもたらします。不要な複雑さを排除することは近道ではありません。より良いソフトウェアを書くための鍵です。
MSalters 2011年

回答:


148

最も効率的な方法は、数字以外の文字が見つかるまで文字列を反復処理することです。数字以外の文字がある場合は、文字列を数値ではないと見なすことができます。

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(), [](unsigned char c) { return !std::isdigit(c); }) == s.end();
}

以下のコメントで指摘されているように、これは正の整数に対してのみ機能します。負の整数または分数を検出する必要がある場合は、より堅牢なライブラリベースのソリューションを使用する必要があります。ただし、負の整数のサポートを追加するのは非常に簡単です。


6
また、負の数値や整数以外の数値は処理しません。質問に基づく要件は何なのかわかりません。
ブレナンヴィンセント

76
!s.empty() && s.find_first_not_of("0123456789") == std::string::npos;C ++ 03ワンライナーにも使用できます。
kbjorklu 2011年

8
また、10進数も処理しません。例:1.23
littlecodefarmer758

3
@レミー・ルボー、そうですね。実際には文字列をに変換していませんint。文字列が数字で構成されているかどうかを識別するだけです。文字列の長さは関係ありません。
Charles Salvia 2013年

5
含めることを忘れてはいけない<string> <algorithm><cctype>C ++ 11の例を動作させるために。
kR105 2014年

88

なぜ車輪を再発明するのですか?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")で16進および8進定数を許可する場合は、0代わりに最後のパラメーターを作成します。

関数は次のように書くことができます

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

4
この関数は、前の空白を破棄します。したがって、最初の文字でisdigitを確認する必要があります。
chmike 2013年

1
@chmike:質問に対する私の理解に基づくと、先頭の空白を破棄することが正しい動作です(atoi質問で使用されているように、これも同じです)。
Ben Voigt 2013年

1
質問では明示的に指定していませんが、「文字列が数値であるかどうかをチェックする」という要件についての私の理解は、文字列全体が数値であるため、スペースがないことを意味します。この点であなたの答えは他の人とは異なることを指摘する必要性を感じました。文字列に数字の前にスペースを入れてもかまわない場合は、あなたの答えはうまくいくかもしれません。
chmike 2013

1
@BenVoigtあなたはそれpが成功したnullptr場合に設定されますよねstrtol?それは私が見ているものではありません:(
Jonathan Mee

2
@JonathanMee:いいえ、p文字列を終了するNULをポイントします。だからp != 0*p == 0
Ben Voigt 2014年

33

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


1
これが最良の答えです。
マーティンブロードハースト2017年

文字列にutf8文字がある場合、ランタイムエラーが発生します。
ライオンキング

29

boost :: lexical_castでC ++の方法で行うことができます。あなたが本当にブーストを使わないことを主張するなら、あなたはそれが何をするかを調べてそれをすることができます。とても簡単です。

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

21
try{} catch{}良いアイデアを使用していますか?できるだけ避けてはいけませんか?
Nawaz、2011年

32
-1トライキャッチを乱用のための... blogs.msdn.com/b/ericlippert/archive/2008/09/10/...
NoSenseEtAl

14
ここではtry {} catch {}が適切です。ただし、catch(...)は単に悪い習慣です。この場合、例外ハンドラーにはboost :: bad_lexical_castを使用します。
NuSkooler 2013

5
これはファイルから読み取ろうとしているような気がします。どんなにファイルをチェックしても、それを行うまでファイルから読み取ることができるかどうかはわかりません。それはうまくいくかそうでないかです。その場合、例外をキャッチする必要があります。この場合、私はこれが完全にうまくいく方法だと思います。
ケーシー

4
@EarlGray-私は確かにウィンドウがとるOS依存のアクションを聞くことに興味があります。標準は、このコードがどのように動作するかについて非常に明確です。
Edward Strange

16

私は反復を使用するこのアイデアを投入したかっただけですが、他のいくつかのコードはその反復を実行します:

#include <string.h>

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

小数点やマイナス記号をチェックする場合のように堅牢ではありません。それぞれの場所や場所に複数存在する可能性があるためです。良い点は、それが1行のコードであり、サードパーティのライブラリを必要としないことです。

「。」を取り出します 許可されるすべてが正の整数の場合は「-」。


エラー:「strspn」はこのスコープで宣言されていなかった私は、「の#include」が、どのような1行方不明ですので、これはあると思う
Qwertie

4
を使用する場合はstd::string、そのfind_first_not_ofメンバー関数を使用します。
Ben Voigt 2014

5
「12.3-4.55-」という文字列を渡すと、これは失敗します。これは明らかに有効な数値ではありません
Buzzrick

バズリック、提案された回答はすでに、これがあなたが言及した非数で失敗するであろうと述べています。
David Rector

「0123456789」のみに制限すると、式は符号なし整数をテストするのに最適です
特別な人はいません。

16

正規表現のアプローチをお勧めします。完全な正規表現一致(例:boost :: regexの使用)

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

文字列が数値かどうかを示します。これには、正と負の数、整数、小数が含まれます。

その他のバリエーション:

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

(ポジティブのみ)

-?[0-9]+

(整数のみ)

[0-9]+

(正の整数のみ)


Ahem、私はstd::regexgcc 4.7、gcc 4.8で使用しようとしました-どちらも、無実の「[abc]」であっても、正規表現でstd::regex_error任意の記号をスローします[(私はそれを間違っていますか?)。clang-3.4はまったく認識していません<regex>。とにかく、これは正直な答えのようです、+ 1。
Dmytro Sirenko 2013

3
@EarlGray:RegexはGCC 4.9からのみ適切に利用可能
オービットの

13

<regex>ライブラリを使用して行う別の方法を次に示します。

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

ああ、そうでしょう。私はより良い解決策で更新しました。ありがとう。
mpataki14 2014年

「[(-| +)|] [0-9] +」ではなく(スターの代わりにプラス)、それ以外の場合、正規表現は「-」または「+」を有効な数値として一致させることができます。
David Mulder

いいね。(、|および)が最初の文字クラスで何をしているのかわかりません。これらのメタ文字は、私が知る限り、文字クラス内で特別な意味を失います。「^ [-+]?[0-9] + $」はどうですか?
U007D 2015

それは非効率的かもしれません。これが呼び出されるたびに、正規表現をコンパイルするstd :: regexコンストラクターが呼び出されます。
user31264

12

このソリューションを使用すると、負の数から正の数、さらには浮動小数点数まですべてをチェックできます。のタイプ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 ++プログラム


10

次のコードが最も堅牢であることがわかりました(c ++ 11)。整数と浮動小数点の両方をキャッチします。

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

ラインusing namespace std;は不要のようです。
Xam 2018

5

正の整数をチェックするためのソリューションは次のとおりです。

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

5

これを試して:

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

1
これだけ符号なし整数のためのテスト
誰も特別な

4

ブレンダンこれ

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"は、Tony Dが指摘したようにtrueを返します。



3

C ++ 11正規表現(#include <regex>)を使用した私のソリューションはunsigned intdoubleなどのより正確なチェックに使用できます。

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にあります。これは、要件を満たすように簡単に変更できます。


私は問題を理解するのを助けるために反対投票者に要求します、私は私の答えを改善します。ありがとう。
aniliitb10 2018

2

kbjorkluのコメントに基づく解決策は次のとおりです。

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

David Rectorの回答と同様に、複数のドットまたはマイナス記号を含む文字列に対して堅牢ではありませんが、それらの文字を削除して整数をチェックすることができます。


ただし、私はBen Voigtの解決策に基づく解決策strtod10進数の値、科学的/工学的表記法、16進表記法(C ++ 11)、またはINF / INFINITY / NAN(C ++ 11)を探すために使用しています。です:

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

2

stringstream クラスを使用できます。

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

       stream<<str;
       stream>>number;

       return stream.eof();
    }

2

を使用し<regex>ます。このコードはテストされました!

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

1

ドキュメンテーションをもう少し調べた後、自分のニーズをサポートする答えを思いつきましたが、おそらく他の人には役に立たないでしょう。ここにあります(迷惑なreturn trueとreturn falseステートメントなし:-))

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

4
数が偶然の場合、0偽陰性になります。
Charles Salvia

3
これは任意の先行番号を返し、後続のゴミを警告しません(例: "123hello" ==> 123)。@Charles:Brendanは、別の回答のコメントで肯定的なintを認識するだけでよいと述べています。
Tony Delroy、2011年

1

この正規表現はほとんどすべてのケースを処理する必要があると思います

"^(\\-|\\+)?[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
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;

}

Intの検証用(ネガティブあり)

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
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 >>オーバーロードは、文字列をさまざまな算術型に変換できます。これは、文字列(この場合はss)から文字がなくなるまで、または次の文字が格納される基準を満たさなくなるまで文字を順次読み取ることによって行われます。宛先変数タイプに。

例1:

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

例2:

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

例3:

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

「ガベージ」変数の説明」:

私のdoubleへの抽出に有効な値があるかどうかを確認し、有効な場合はtrueを返すのはなぜですか?

上記のexample3は、入力文字列が "11ABCD"(数値ではない)の場合でも、数値11をmy_number変数に正常に読み取ることに注意してください。

このケースを処理するために、文字列変数(私はgarbageと名付けました)への別の抽出を行うことができます。何かが残っている場合は、「ガベージ」に読み込まれます。これは、渡された文字列全体が数値ではなかったことを意味します(1で始まるだけです)。この場合、falseを返します。

先頭に「0の説明」:

単一の文字をdoubleに抽出しようとすると失敗します(doubleに0が返されます)が、文字列バッファの位置は文字の後に移動します。この場合、ガベージリードは空になるため、関数は誤ってtrueを返します。これを回避するために、文字列の先頭に0を追加しました。たとえば、渡された文字列が「a」の場合、「0a」に変更されて、0がdoubleに抽出され、「a」がゴミに抽出されます。

先頭に0を付けても数値の値には影響しないため、数値は引き続きdouble変数に正しく抽出されます。


1
このコードは質問に答えることがありますが、このコードが質問に答える理由や方法に関する追加のコンテキストを提供すると、長期的な価値が向上します。
Ajean 2015年

1

文字列が整数または浮動小数点かどうかを確認するには、次のように使用できます。

 #include <sstream>

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

1
これは、値「10_is_not_a_number」を含む文字列に対して10を返します。
KorreyD 2015年

1

さらに別の答えは、それを使用します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);
}


1

これを試して:

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

boost :: lexical_castを使用して、文字列が整数に変換可能かどうかをテストできます。bad_lexical_cast例外をスローする場合、文字列は変換できませんでした。それ以外の場合は変換できます。

以下のそのようなテストプログラムの例を参照してください。

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

実行例:

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

0

数か月前、文字列が整数、16進数、または2倍であるかどうかを判断する方法を実装しました。

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として処理できます。


0

私は簡単な規則を提案します:

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

この関数は、考えられるすべてのケースを処理します。

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

sscanfの戻りコードを使用して、それがintかどうかを判断できますか?

bool is_number(const std::string& s)
{
    int value;
    int result = sscanf(valueStr.c_str(), "%d", &value);
    return (result != EOF && readResult != 0);
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.