または、他の方法から最初の数字以外の文字を見つけます。
同じ機能が文字列とchar *に適用されますか?
もちろん、数字のみの文字列をテストする多くの方法があります。次の2つの方法があります。
bool is_digits(const std::string &str)
{
return str.find_first_not_of("0123456789") == std::string::npos;
}
または
bool is_digits(const std::string &str)
{
return std::all_of(str.begin(), str.end(), ::isdigit); // C++11
}
すでにisdigit()
を使用するように言及している人々がいます。ただし、char
に署名すると負の値がisdigit()
に渡される可能性があるため、これは完全に簡単ではありません。ただし、この関数は正の値のみを取ることができます。つまり、次のようなものが必要です。
if (s.end() == std::find_if(s.begin(), s.end(),
[](unsigned char c)->bool { return !isdigit(c); })) {
std::cout << "string '" << s << "' contains only digits\n";
}
unsigned char
への変換の理由は明らかではないようです。そのため、それぞれの標準からの関連する引用を以下に示します。
ISO/IEC 9899:2011(またはISO/IEC 9899:1999)7.4パラグラフ1によると、<ctype.h>
の関数の引数には次が適用されます。
...すべての場合において、引数は
int
であり、その値はunsigned char
として表現可能であるか、マクロEOF
の値と等しくなければなりません。引数に他の値がある場合、動作は未定義です。
残念ながら、C++標準ではchar
が符号なしの型であることを指定していません。代わりに、ISO/IEC 14882:2011 3.9.1 [basic.fundamental]パラグラフ1で指定しています。
...
char
オブジェクトが負の値を保持できるかどうかは実装定義です。 ...
明らかに、負の値はunsigned char
として表すことはできません。つまり、char
が実装で署名された型を使用している場合(実際にはgccまたはclangを使用してMacOSで署名されているなど)、<ctype.h>
関数のいずれかを呼び出す危険性があります未定義の動作を引き起こします。
さて、なぜunsigned char
への変換が正しいことをするのでしょうか?
4.7 [conv.integral]パラグラフ2によると:
宛先タイプが符号なしの場合、結果の値は、ソース整数と一致する最小の符号なし整数です(モジュロ2n ここで、nは符号なしの型を表すために使用されるビット数です)。 [注:2の補数表現では、この変換は概念的なものであり、ビットパターンに変更はありません(切り捨てがない場合)。 —注を終了]
つまり、[潜在的に]署名されたchar
からunsigned char
への変換は明確に定義されており、結果は<ctype.h>
関数で許可された範囲内になります。
isdigit(int)
は、文字が数字かどうかを示します。 ASCIIおよび10を基数とする場合は、以下も使用できます。
int first_non_digit_offset= strspn(string, "0123456789")
ミーシャの答えと同じ精神で、しかしより正確に:sscanf(buf, "%*u%*c")==1
。
scanf
は、%d
数字の抽出に失敗した場合は0を返し、%c
によってキャプチャされた数字の後に何かがある場合は2を返します。 *
は値の保存を妨げるため、オーバーフローすることさえありません。
cctype
ヘッダーファイルには、文字列の各文字で使用できる文字分類関数が多数あります。数値チェックの場合、isdigit
になります。
次のプログラムは、CまたはC++文字列の各文字をチェックする方法を示しています(プロセスは実際の文字をチェックするという点ではほとんど同じですが、唯一の違いは長さの取得方法です)。
#include <iostream>
#include <cstring>
#include <cctype>
int main (void) {
const char *xyzzy = "42x";
std::cout << xyzzy << '\n';
for (int i = 0; i < std::strlen (xyzzy); i++) {
if (! std::isdigit (xyzzy[i])) {
std::cout << xyzzy[i] << " is not numeric.\n";
}
}
std::string plugh ("3141y59");
std::cout << plugh << '\n';
for (int i = 0; i < plugh.length(); i++) {
if (! std::isdigit (plugh[i])) {
std::cout << plugh[i] << " is not numeric.\n";
}
}
return 0;
}
cplusplus.com から、次のようにisdigit関数を使用できます。
// isdigit example (C++)
#include <iostream> // std::cout
#include <string> // std::string
#include <locale> // std::locale, std::isdigit
#include <sstream> // std::stringstream
int main ()
{
std::locale loc;
std::string str="1776ad";
if (isdigit(str[0],loc))
{
int year;
std::stringstream(str) >> year;
std::cout << "The year that followed " << year << " was " << (year+1) << ".\n";
}
return 0;
}
注:isdigitには2種類あり、他のバージョンはローカルに依存せず、ASCIIベース。
#include <regex>
std::string string( "I only have 3 dollars!" );
std::cout << std::regex_search( string, std::regex( "\\d+" ) ); // true
そして
std::string string( "I only have three dollars!" );
std::cout << std::regex_search( string, std::regex( "\\d+" ) ); // false
最初の文字以外の数字がどこにあるかを正確に見つけることが厳密な要件である場合は、各文字をチェックする必要があります。そうでない場合は、次のいずれかを使用します。
unsigned safe_atoi(const std::string& a)
{
std::stringstream s(a);
unsigned b;
s >> b;
return b;
}