はじめに
stox系(C++11)が使えない環境の場合にatoi/atofの強化版を自作してみた記事になります
文字列→数値変換の基本
atoi/atofでは数値以外の文字列が入った場合、エラーにならず0を返すという仕様になっています
下記のように記述して出力してみました
void OutputLog( const std::string& str )
{
try
{
std::cout << str << "をatoiで変換:" << atoi( str.c_str() ) << std::endl;
}
catch( std::exception e )
{
std::cout << str << "の変換に失敗!!" << std::endl;
}
try
{
std::cout << str << "をatofで変換:" << atof( str.c_str() ) << std::endl;
}
catch( std::exception e )
{
std::cout << str << "の変換に失敗!!" << std::endl;
}
std::cout << std::endl;
}
int main()
{
OutputLog( "" );
OutputLog( "0aaa" );
OutputLog( "00aaa" );
OutputLog( "-00aaa" );
OutputLog( "-0aaa" );
OutputLog( "009" );
OutputLog( " 12345" );
OutputLog( " 12345" ); // 全角スペース
OutputLog( " \t \n \r 12345" );
OutputLog( " \t \n \r 0" );
OutputLog( "-.32f" );
OutputLog( "あああああ" );
OutputLog( "-あああああ" );
OutputLog( "01弐参" );
OutputLog( "零壱23" );
return 0;
}
出力結果↓
をatoiで変換:0
をatofで変換:0
0aaaをatoiで変換:0
0aaaをatofで変換:0
00aaaをatoiで変換:0
00aaaをatofで変換:0
-00aaaをatoiで変換:0
-00aaaをatofで変換:-0
-0aaaをatoiで変換:0
-0aaaをatofで変換:-0
009をatoiで変換:9
009をatofで変換:9
12345をatoiで変換:12345
12345をatofで変換:12345
12345をatoiで変換:0
12345をatofで変換:0
12345をatoiで変換:12345
12345をatofで変換:12345
0をatoiで変換:0
0をatofで変換:0
-.32fをatoiで変換:0
-.32fをatofで変換:-0.32
あああああをatoiで変換:0
あああああをatofで変換:0
-あああああをatoiで変換:0
-あああああをatofで変換:0
01弐参をatoiで変換:1
01弐参をatofで変換:1
零壱23をatoiで変換:0
零壱23をatofで変換:0
エラーにはならず、0が返ってきてしまいます
これをエラーにする判定処理を入れて作ってみました
判定処理を作ってみた
// 文字列の置換
void ReplaceStart( std::string& inoutStr, const std::string& oldStr, const std::string& newStr )
{
size_t str_pos = 0;
std::string::size_type pos( GetFirstPos( inoutStr, oldStr ) );
while( str_pos + oldStr.length() < inoutStr.length() && pos == str_pos )
{
inoutStr.replace( pos, oldStr.length(), newStr );
pos = GetFirstPos( &inoutStr[ pos + newStr.length() ], oldStr );
str_pos += newStr.length();
}
}
// 文字列の前の空白や改行を除去する
void TrimStart( std::string& inoutStr )
{
while( inoutStr.front() == ' ' ||
inoutStr.front() == '\n' ||
inoutStr.front() == '\r' ||
inoutStr.front() == '\t' )
{
ReplaceStart( inoutStr, " ", "" );
ReplaceStart( inoutStr, "\n", "" );
ReplaceStart( inoutStr, "\r", "" );
ReplaceStart( inoutStr, "\t", "" );
}
}
// 文字列を数値に変換する
template<typename T>
T ConvertToNum( const std::string& numStr ) // 文字の先頭にあるスペースを削除して数値を取得する
{
std::string bufStr = numStr;
double checkNum = atof( numStr.c_str() );
T convertNum = ( T ) checkNum;
TrimStart( bufStr );
if( checkNum == 0 && bufStr.front() != '0' && ( bufStr[ 0 ] == '-' && bufStr[ 1 ] == '0' ) == false )
{
throw std::invalid_argument( "この文字列は変換できません" );
}
return convertNum;}
GetFirstPosは下記で記述してるので今回は割愛
最初に空白がある可能性があるので取り除いた後にatofで変換し、変換した値が0の場合に本当に0なのかチェックをしています
先程のチェックコードに作った関数を入れて確認してみます
void OutputLog( const std::string& str )
{
try
{
std::cout << str << "をatoiで変換:" << atoi( str.c_str() ) << std::endl;
}
catch( std::exception e )
{
std::cout << str << "の変換に失敗!!" << std::endl;
}
try
{
std::cout << str << "をatofで変換:" << atof( str.c_str() ) << std::endl;
}
catch( std::exception e )
{
std::cout << str << "の変換に失敗!!" << std::endl;
}
std::cout << std::endl;
try
{
int num = ConvertToNum<int>( str );
std::cout << str << "をintに変換:" << num << std::endl;
}
catch( std::exception e )
{
std::cout << str << "の変換に失敗!!" << std::endl;
}
try
{
float num = ConvertToNum<float>( str );
std::cout << str << "をfloatに変換:" << num << std::endl;
}
catch( std::exception e )
{
std::cout << str << "の変換に失敗!!" << std::endl;
}
try
{
float num = ConvertToNum<double>( str );
std::cout << str << "をdoubleに変換:" << num << std::endl;
}
catch( std::exception e )
{
std::cout << str << "の変換に失敗!!" << std::endl;
}
std::cout << std::endl;
}
結果↓
をatoiで変換:0
をatofで変換:0
の変換に失敗!!
の変換に失敗!!
の変換に失敗!!
0aaaをatoiで変換:0
0aaaをatofで変換:0
0aaaをintに変換:0
0aaaをfloatに変換:0
0aaaをdoubleに変換:0
00aaaをatoiで変換:0
00aaaをatofで変換:0
00aaaをintに変換:0
00aaaをfloatに変換:0
00aaaをdoubleに変換:0
-00aaaをatoiで変換:0
-00aaaをatofで変換:-0
-00aaaをintに変換:0
-00aaaをfloatに変換:-0
-00aaaをdoubleに変換:-0
-0aaaをatoiで変換:0
-0aaaをatofで変換:-0
-0aaaをintに変換:0
-0aaaをfloatに変換:-0
-0aaaをdoubleに変換:-0
009をatoiで変換:9
009をatofで変換:9
009をintに変換:9
009をfloatに変換:9
009をdoubleに変換:9
12345をatoiで変換:12345
12345をatofで変換:12345
12345をintに変換:12345
12345をfloatに変換:12345
12345をdoubleに変換:12345
12345をatoiで変換:0
12345をatofで変換:0
12345の変換に失敗!!
12345の変換に失敗!!
12345の変換に失敗!!
12345をatoiで変換:12345
12345をatofで変換:12345
12345をintに変換:12345
12345をfloatに変換:12345
12345をdoubleに変換:12345
0をatoiで変換:0
0をatofで変換:0
0をintに変換:0
0をfloatに変換:0
0をdoubleに変換:0
-.32fをatoiで変換:0
-.32fをatofで変換:-0.32
-.32fをintに変換:0
-.32fをfloatに変換:-0.32
-.32fをdoubleに変換:-0.32
あああああをatoiで変換:0
あああああをatofで変換:0
あああああの変換に失敗!!
あああああの変換に失敗!!
あああああの変換に失敗!!
-あああああをatoiで変換:0
-あああああをatofで変換:0
-あああああの変換に失敗!!
-あああああの変換に失敗!!
-あああああの変換に失敗!!
01弐参をatoiで変換:1
01弐参をatofで変換:1
01弐参をintに変換:1
01弐参をfloatに変換:1
01弐参をdoubleに変換:1
零壱23をatoiで変換:0
零壱23をatofで変換:0
零壱23の変換に失敗!!
零壱23の変換に失敗!!
零壱23の変換に失敗!!