文字列値が浮動小数点数として「適格」であるかどうかを判断する便利な方法を知っている人はいますか?
bool IsFloat( string MyString )
{
... etc ...
return ... // true if float; false otherwise
}
Boostライブラリ関数を使用できない場合は、次のように独自のisFloat関数を作成できます。
#include <string>
#include <sstream>
bool isFloat( string myString ) {
std::istringstream iss(myString);
float f;
iss >> noskipws >> f; // noskipws considers leading whitespace invalid
// Check the entire string was consumed and if either failbit or badbit is set
return iss.eof() && !iss.fail();
}
Boostのlexical_castが好きかもしれません( http://www.boost.org/doc/libs/1_37_0/libs/conversion/lexical_cast.htm を参照)。
bool isFloat(const std::string &someString)
{
using boost::lexical_cast;
using boost::bad_lexical_cast;
try
{
boost::lexical_cast<float>(someString);
}
catch (bad_lexical_cast &)
{
return false;
}
return true;
}
Boostを必要としないように、istreamを使用できますが、率直に言って、Boostは除外するにはあまりにも優れています。
インスピレーション この回答 文字列が浮動小数点数であるかどうかをチェックするように関数を変更しました。ブーストを必要とせず、stringstreamsfailbitに依存しません-単なる解析です。
static bool isFloatNumber(const std::string& string){
std::string::const_iterator it = string.begin();
bool decimalPoint = false;
int minSize = 0;
if(string.size()>0 && (string[0] == '-' || string[0] == '+')){
it++;
minSize++;
}
while(it != string.end()){
if(*it == '.'){
if(!decimalPoint) decimalPoint = true;
else break;
}else if(!std::isdigit(*it) && ((*it!='f') || it+1 != string.end() || !decimalPoint)){
break;
}
++it;
}
return string.size()>minSize && it == string.end();
}
つまり.
1
2.
3.10000
4.2f
-5.3f
+6.2f
この関数によってfloatとして正しく認識されます。
1.0.0
2f
2.0f1
無効なフロートの例です。 X.XXf形式の浮動小数点数を認識したくない場合は、次の条件を削除してください。
&& ((*it!='f') || it+1 != string.end() || !decimalPoint)
9行目から。「。」のない数字を認識したくない場合。 floatとして(つまり、「1」ではなく、「1。」、「1.0」、「1.0f」のみ...)、最後の行を次のように変更できます。
return string.size()>minSize && it == string.end() && decimalPoint;
ただし、boostのlexical_castを使用するか、この「醜い関数」ではなくstringstreamsを使用するソリューションを使用する理由はたくさんあります。ただし、浮動小数点数として正確に認識したい形式の種類(つまり、小数点以下の最大桁数...)をより細かく制御できます。
最近、文字列が数字かどうかをチェックする関数を書きました。この数値は整数または浮動小数点数にすることができます。
私のコードをひねって、いくつかのユニットテストを追加することができます。
bool isNumber(string s)
{
std::size_t char_pos(0);
// skip the whilespaces
char_pos = s.find_first_not_of(' ');
if (char_pos == s.size()) return false;
// check the significand
if (s[char_pos] == '+' || s[char_pos] == '-') ++char_pos; // skip the sign if exist
int n_nm, n_pt;
for (n_nm = 0, n_pt = 0; std::isdigit(s[char_pos]) || s[char_pos] == '.'; ++char_pos) {
s[char_pos] == '.' ? ++n_pt : ++n_nm;
}
if (n_pt>1 || n_nm<1) // no more than one point, at least one digit
return false;
// skip the trailing whitespaces
while (s[char_pos] == ' ') {
++ char_pos;
}
return char_pos == s.size(); // must reach the ending 0 of the string
}
void UnitTest() {
double num = std::stod("825FB7FC8CAF4342");
string num_str = std::to_string(num);
// Not number
assert(!isNumber("1a23"));
assert(!isNumber("3.7.1"));
assert(!isNumber("825FB7FC8CAF4342"));
assert(!isNumber(" + 23.24"));
assert(!isNumber(" - 23.24"));
// Is number
assert(isNumber("123"));
assert(isNumber("3.7"));
assert(isNumber("+23.7"));
assert(isNumber(" -423.789"));
assert(isNumber(" -423.789 "));
}
入力文字列に対して正規表現の一致を実行したいと思います。すべてのEdgeケースをテストするのはかなり複雑かもしれないと思います。
このサイト いくつかの良い情報があります。最後までスキップしたい場合は、^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?$
と表示されます。
正規表現の構文を理解していれば、これは基本的に理にかなっています。
[編集:最初の空白と末尾のナンセンスを禁止するように修正されました。]
#include <sstream>
bool isFloat(string s) {
istringstream iss(s);
float dummy;
iss >> noskipws >> dummy;
return iss && iss.eof(); // Result converted to bool
}
これを、T
の代わりにタイプfloat
でテンプレート化された関数に簡単に変換できます。これは本質的にBoostの lexical_cast が行うことです。
私は似たようなものを探していましたが、これまでに見たものよりもはるかに簡単な答えを見つけました。
bool is_float(float val){
if(val != floor(val)){
return true;
}
else
return false;
}
または:
auto lambda_isFloat = [](float val) {return (val != floor(val)); };
お役に立てれば !
ZMazz
C++で文字列をdoubleに変換するにはどうすればよいですか? で説明されているメソッドを使用でき、conversion_error
をスローする代わりに、false
を返します(文字列がを表していないことを示します) float
)、それ以外の場合はtrue
。
std::stof
を使用したC++ 11ソリューション:
bool isFloat(const std::string& s) {
try {
std::stof(s);
return true;
} catch(...) {
return false;
}
}
エンドポインタを指定できるので、私はいつもstrtof
が好きでした。
bool isFloat(const std::string& str)
{
char* ptr;
strtof(str.c_str(), &ptr);
return (*ptr) == '\0';
}
これは、エンドポインターが解析が失敗し始めた文字を指しているために機能します。したがって、それがヌルターミネーターを指している場合、文字列全体がfloatとして解析されました。
この質問が出回っている10年間、誰もこの方法について言及していなかったことに驚いています。これは、C-Styleの方法であるためだと思います。ただし、C++でも完全に有効であり、どのストリームソリューションよりも洗練されています。また、「+ inf」、「-inf」などで機能し、先頭の空白を無視します。
atof を使用して、0.0
を特別に処理することもできますが、それが特に良い解決策とは見なされないと思います。
これはSOに関する一般的な質問です。 この質問 を見て提案を確認してください(この質問ではstring-> intについて説明していますが、アプローチは同じです)。
注:文字列を変換できるかどうかを知るには、基本的に変換を実行して、オーバーフロー/アンダーフローなどをチェックする必要があります。
できることは、istringstreamを使用して、ストリーム操作の結果に基づいてtrue/falseを返すことです。このようなもの(警告-私はコードをコンパイルしていません、それはガイドラインのみです):
float potential_float_value;
std::istringstream could_be_a_float(MyString)
could_be_a_float >> potential_float_value;
return could_be_a_float.fail() ? false : true;
int isFloat(char *s){
if(*s == '-' || *s == '+'){
if(!isdigit(*++s)) return 0;
}
if(!isdigit(*s)){return 0;}
while(isdigit(*s)) s++;
if(*s == '.'){
if(!isdigit(*++s)) return 0;
}
while(isdigit(*s)) s++;
if(*s == 'e' || *s == 'E'){
s++;
if(*s == '+' || *s == '-'){
s++;
if(!isdigit(*s)) return 0;
}else if(!isdigit(*s)){
return 0;
}
}
while(isdigit(*s)) s++;
if(*s == '\0') return 1;
return 0;
}
atof
関数も同様に機能するため、先頭の空白を無視したくなるでしょう。
この関数は、最初の非空白文字が見つかるまで、最初に必要な数の空白文字を破棄します。次に、この文字から始めて、浮動小数点リテラルの構文に似た構文に従って有効な文字をできるだけ多く取り、それらを数値として解釈します。最後の有効な文字の後の文字列の残りは無視され、この関数の動作には影響しません。
したがって、これに一致させるには、次のようにします。
bool isFloat(string s)
{
istringstream iss(s);
float dummy;
iss >> skipws >> dummy;
return (iss && iss.eof() ); // Result converted to bool
}
それは、信頼のレベル、必要なもの、および入力データの出所によって異なります。データがユーザーからのものである場合は、インポートされたテーブルデータと比較して、より注意する必要があります。インポートされたテーブルデータでは、すべてのアイテムが整数または浮動小数点数であり、それだけを区別する必要があることがわかっています。
たとえば、最速のバージョンの1つは、単に「。」の存在をチェックします。そしてその中の「eE」。ただし、残りがすべて数字であるかどうかを確認することをお勧めします。最初の空白をスキップしますが、途中ではなく、単一の「。」を確認します。 「eE」など.
したがって、q&d高速ハックはおそらくより洗練された正規表現のような(それを呼び出すか自分でスキャンする)アプローチにつながるでしょう。しかし、結果は、フロートのように見えますが、実際にマシンで表現できることをどのように知っていますか(つまり、1.2345678901234567890e1234567890を試してください)。もちろん、仮数/指数に「最大N」桁の正規表現を作成することもできますが、それはマシン/ OS /コンパイラーまたは特定のものである場合があります。
したがって、最終的には、確かに、基盤となるシステムの変換を呼び出して、何が得られるか(例外、無限大、またはNAN)を確認する必要があります。