ユーザーが予想する値が、文字列をatof(str)に渡すことによって返される値(指数表記を含む)と一致することを確認したい場合は、次のコードが機能します。
fgets(str、size、stdin)を使用して入力を取得でき、文字列をパーサーに渡す前に末尾の改行を削除する必要もありません。
また、解析エラーが発生した場合、関数は、追加の引数として渡されたポインターに、原因となる文字の場所を報告します。
読みやすい長い形式と入力しやすい短い形式があります。
長い形式:
/*
Copyright (C) 2010 S. Randall Sawyer
This code is in the public domain. It is intended to be usefully illustrative.
It is not intended to be used for any particular application. If this code is
used in any application - whether open source or proprietary, then please give
credit to the author.
*/
#include <ctype.h>
#define FAILURE (0)
#define SUCCESS (!FAILURE)
enum {
END_EXPRESSION = 0x00,
ALLOW_POINT = 0x01,
ALLOW_NEGATIVE = 0x02,
REQUIRE_DIGIT = 0x04,
ALLOW_EXPONENT = 0x08,
HAVE_EXPONENT = 0x10,
EXPECT_EXPRESSION = ALLOW_POINT | ALLOW_NEGATIVE | REQUIRE_DIGIT,
EXPECT_INTEGER = ~ALLOW_POINT,
EXPECT_POS_EXPRESSION = ~ALLOW_NEGATIVE,
EXPECT_POS_INTEGER = EXPECT_INTEGER & EXPECT_POS_EXPRESSION,
EXPECT_EXPONENT = EXPECT_INTEGER ^ HAVE_EXPONENT,
EXPONENT_FLAGS = REQUIRE_DIGIT | ALLOW_EXPONENT | HAVE_EXPONENT
} DoubleParseFlag;
int double_parse_long ( const char * str, const char ** err_ptr )
{
int ret_val, flags;
const char * ptr;
flags = EXPECT_EXPRESSION;
ptr = str;
do {
if ( isdigit ( *ptr ) ) {
ret_val = SUCCESS;
/* The '+' here is the key: It toggles 'ALLOW_EXPONENT' and
'HAVE_EXPONENT' successively */
flags = ( flags + ( flags & REQUIRE_DIGIT ) ) & EXPECT_POS_EXPRESSION;
}
else if ( (*ptr & 0x5f) == 'E' ) {
ret_val = ( ( flags & ( EXPONENT_FLAGS ) ) == ALLOW_EXPONENT );
flags = EXPECT_EXPONENT;
}
else if ( *ptr == '.' ) {
ret_val = ( flags & ALLOW_POINT );
flags = ( flags & EXPECT_POS_INTEGER );
}
else if ( *ptr == '-' ) {
ret_val = ( flags & ALLOW_NEGATIVE );
flags = ( flags & EXPECT_POS_EXPRESSION );
}
else if ( iscntrl ( *ptr ) ) {
ret_val = !( flags & REQUIRE_DIGIT );
flags = END_EXPRESSION;
}
else {
ret_val = FAILURE;
flags = END_EXPRESSION;
}
ptr++;
} while (ret_val && flags);
if (err_ptr != NULL)
*err_ptr = ptr - 1;
return ret_val;
}
ショートフォーム:
/*
Copyright (C) 2010 S. Randall Sawyer
This code is in the public domain. It is intended to be usefully illustrative.
It is not intended to be used for any particular application. If this code is
used in any application - whether open source or proprietary, then please give
credit to the author.
*/
#include <ctype.h>
int double_parse_short ( const char * str, const char ** err_ptr )
{
int ret_val, flags;
const char * ptr;
flags = 0x07;
ptr = str;
do {
ret_val = ( iscntrl ( *ptr ) ) ? !(flags & 0x04) : (
( *ptr == '.' ) ? flags & 0x01 : (
( *ptr == '-' ) ? flags & 0x02 : (
( (*ptr & 0x5f) == 'E' ) ? ((flags & 0x1c) == 0x08) : (
( isdigit ( *ptr ) ) ? 1 : 0 ) ) ) );
flags = ( isdigit ( *ptr ) ) ?
(flags + (flags & 0x04)) & 0x1d : (
( (*ptr & 0x5f) == 'E' ) ? 0x0e : (
( *ptr == '-' ) ? flags & 0x1d : (
( *ptr == '.' ) ? flags & 0x1c : 0 ) ) );
ptr++;
} while (ret_val && flags);
if (err_ptr != NULL)
*err_ptr = ptr - 1;
return ret_val;
}
これがお役に立てば幸いです。