ホーム

OFF-SOFT.net

OFF-SOFT.net

ウェブやソフトウェアに関するサポート&情報サイトです。サイト構築からソフトウェアの作成、利用まであなたの助けになるかも・・・・しれません。たぶん・・。

Boost(4)lexical_castとatoi,atofを調べる

公開日| 2009年09月10日 | コメントはまだありません。
概要 :
 今回の記事は、Boostで色々な情報へキャストすることができるlexical_castを使ってみます。
lexical_castは、STLのstringからdoubleやintへの変換もできます。C言語では、atof,atoi などを使って変換します。 C++では、std::istringstreamからのシフト演算子(>>)を使って変換できます。

上記の3つの違いについて、簡単に調べてみたいと思います。
では、早速、サンプルソースを使って試してみましょう。

ここで使用したサンプルソースコード:

コンソールアプリケーションで試してみましょう
簡単に動作確認するために、以下のようなサンプルプログラムを作成してみました。
では、早速、ソースコードを見てみましょう。

[sample.cpp]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#include <iostream>
#include <string>
 
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
 
using namespace std;
using namespace boost;
 
struct _test_value {
	const char *_char;
	const wchar_t *_wchar;
};
static _test_value double_test[] =
{
	{	"hello world!123"	,	L"hello world!123"	},
	{	"12345"	,	L"12345"	},
	{	" 12345"	,	L" 12345"	},
	{	"12345 "	,	L"12345 "	},
	{	" 12345 "	,	L" 12345 "	},
	{	"123.45"	,	L"123.45"	},
	{	"6.543E+099"	,	L"6.543E+099"	},
	{	"6.543e+099"	,	L"6.543e+099"	},
	{	"1.2345e+999"	,	L"1.2345e+999"	},
 
	//	stopper
	{ NULL,NULL }
};
 
int main(int argc, char *argv[])
{
	string str1;
	wstring str2;
 
	double db;
	int ni=0;
	cout << "== double convert"  << endl;
	while(double_test[ni]._char!=NULL){
 
		str1=double_test[ni]._char;
		str2=double_test[ni]._wchar;
 
		try{
			db=lexical_cast<double>(str1);
			cout << str1 << ":"<< db << endl;
		} catch(bad_lexical_cast &e) {
			cout << str1 << "(error):" << e.what() << endl;
		}
 
		try{
			db=lexical_cast<double>(str2);
			cout << str1 << ":"<<  db << endl;
		} catch(bad_lexical_cast &e) {
			cout << str1 << "(error):"  << e.what() << endl;
		}
 
		std::istringstream ss(str1);
		//std::wistringstream ss(str2);
		ss >> db;
		if(!(ss && (ss >> std::ws).eof())){
			cout << "cast(error):"<< str1 <<  ":"<<  db << endl;
		} else {
			cout << "cast:"<< str1 <<  ":"<<  db << endl;
		}
 
		db=atof(str1.c_str());
		cout << "atof:"<< str1 << ":"<<  db << endl;
		cout << endl;
		ni++;
	}
	int nb;
	ni=0;
	cout << "== int convert"  << endl;
	while(double_test[ni]._char!=NULL){
 
		str1=double_test[ni]._char;
		str2=double_test[ni]._wchar;
 
		try{
			nb=lexical_cast<int>(str1);
			cout << str1 << ":"<< nb << endl;
		} catch(bad_lexical_cast &e) {
			cout << str1 << "(error):" << e.what() << endl;
		}
 
		try{
			nb=lexical_cast<int>(str2);
			cout << str1 << ":"<<  nb << endl;
		} catch(bad_lexical_cast &e) {
			cout << str1 << "(error):"  << e.what() << endl;
		}
 
		std::istringstream ss(str1);
		ss >> nb;
		if(!(ss && (ss >> std::ws).eof())){
			cout << "cast(error):"<< str1 << ":"<<  nb << endl;
		} else {
			cout << "cast:"<< str1 << ":"<<  nb << endl;
		}
 
		nb=atoi(str1.c_str());
		cout << "atoi:"<< str1 << ":"<<  nb << endl;
		cout << endl;
		ni++;
	}
 
 
	string strss;
	cin >> strss ;	//	any key input!! --> exit.
	return 1;
}

このプログラムは、double_testのテストデータ(8bit文字列、UNCODE文字列)を順次変換して、 その結果を出力しています。UNCODE文字列については、lexical_castでのみ変換しています。

では、簡単に解説をしてみます。
38行目は、テストデータが終わりかどうかを判断しています。
44行目、51行目は、lexical_castによるdoubleへの変換処理を実施しています。変換に失敗するとbad_lexical_castがスローされます。
変換の仕方は、以下のように指定します。戻り値が、変換結果となります。
lexical_cast<変換したいクラス名>(変換するオブジェクト)

57行目から64行目は、C++言語のSTLを用いた変換を行っています。 60行目でエラーチェックを行っていますが、今回は、すべての文字列が変換処理を実施したかどうかで判断しています。
66行目は、C言語によ変換を行っています。atof,atoiでは、エラーの確認はできません。

以降は、intへの変換です。処理の概要は同じですので、説明を割愛いたします。


実際に、実行してみると、以下がその実行結果が表示されます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
== double convert
hello world!123(error):bad lexical cast: source type value could not be interpreted as target
hello world!123(error):bad lexical cast: source type value could not be interpreted as target
cast(error):hello world!123:-9.25596e+061
atof:hello world!123:0
 
12345:12345
12345:12345
cast:12345:12345
atof:12345:12345
 
 12345(error):bad lexical cast: source type value could not be interpreted as target
 12345(error):bad lexical cast: source type value could not be interpreted as target
cast: 12345:12345
atof: 12345:12345
 
12345 (error):bad lexical cast: source type value could not be interpreted as target
12345 (error):bad lexical cast: source type value could not be interpreted as target
cast:12345 :12345
atof:12345 :12345
 
 12345 (error):bad lexical cast: source type value could not be interpreted as target
 12345 (error):bad lexical cast: source type value could not be interpreted as target
cast: 12345 :12345
atof: 12345 :12345
 
123.45:123.45
123.45:123.45
cast:123.45:123.45
atof:123.45:123.45
 
6.543E+099:6.543e+099
6.543E+099:6.543e+099
cast:6.543E+099:6.543e+099
atof:6.543E+099:6.543e+099
 
6.543e+099:6.543e+099
6.543e+099:6.543e+099
cast:6.543e+099:6.543e+099
atof:6.543e+099:6.543e+099
 
1.2345e+999(error):bad lexical cast: source type value could not be interpreted as target
1.2345e+999(error):bad lexical cast: source type value could not be interpreted as target
cast(error):1.2345e+999:6.543e+099
atof:1.2345e+999:1.#INF
 
== int convert
hello world!123(error):bad lexical cast: source type value could not be interpreted as target
hello world!123(error):bad lexical cast: source type value could not be interpreted as target
cast(error):hello world!123:-858993460
atoi:hello world!123:0
 
12345:12345
12345:12345
cast:12345:12345
atoi:12345:12345
 
 12345(error):bad lexical cast: source type value could not be interpreted as target
 12345(error):bad lexical cast: source type value could not be interpreted as target
cast: 12345:12345
atoi: 12345:12345
 
12345 (error):bad lexical cast: source type value could not be interpreted as target
12345 (error):bad lexical cast: source type value could not be interpreted as target
cast:12345 :12345
atoi:12345 :12345
 
 12345 (error):bad lexical cast: source type value could not be interpreted as target
 12345 (error):bad lexical cast: source type value could not be interpreted as target
cast: 12345 :12345
atoi: 12345 :12345
 
123.45(error):bad lexical cast: source type value could not be interpreted as target
123.45(error):bad lexical cast: source type value could not be interpreted as target
cast(error):123.45:123
atoi:123.45:123
 
6.543E+099(error):bad lexical cast: source type value could not be interpreted as target
6.543E+099(error):bad lexical cast: source type value could not be interpreted as target
cast(error):6.543E+099:6
atoi:6.543E+099:6
 
6.543e+099(error):bad lexical cast: source type value could not be interpreted as target
6.543e+099(error):bad lexical cast: source type value could not be interpreted as target
cast(error):6.543e+099:6
atoi:6.543e+099:6
 
1.2345e+999(error):bad lexical cast: source type value could not be interpreted as target
1.2345e+999(error):bad lexical cast: source type value could not be interpreted as target
cast(error):1.2345e+999:1
atoi:1.2345e+999:1

この結果を簡単に表にまとめてみました。

  Boost lexical std::istringstream atoi/atof
文字列あり x x x (0)
整数値 o o o
整数値(空白あり(前)) x o o
整数値(空白あり(後)) x o o
整数値(空白あり(前後)) x o o
小数値 o o (*1) o (*1)
小数値(E表現) o o (*1) o (*1)
小数値(e表現) o o (*1) o (*1)
小数値(e表現オーバーフロー値) x x (*1) x (*1)
*1:int変換では、先頭からの整数部分のみは取り出せる。

このように、lexical_castのチェックは、非常に厳格です。
前後の半角ブランクがあるだけでもNGとなります。
それに比べて、C/C++での変換は、半角ブランクがあっても変換できます。

昨今では、atoi,atofを多用しているプログラムは、あまり無いとは思いますが、 atoi,atofの代わりに、lexical_castをそのまま用いようとするとエラーが発生して、うまく動作しないかもしれませんね。

また、lexical_castは、int,doubleなどの数値変換だけでなく、数値から文字列への変換などもできます。非常に便利なものです。
色々と試されることをお勧めします。


もっと、Boostについて詳しく知りたい方は、以下の本なども良いと思います。
本から学ぶことは多いと思います。ネットだけでは判らない様々な事に気づかされます。


コメント

コメントをどうぞ







  • はてなブックマークへ追加する
  • Facebookでシェアする
  • twitter でつぶやく
  • Google Plusでシェアする
  • Pocketでシェアする
ページトップへ