ちょっとした質問があります。インターネットでかなり調べて、いくつかの解決策を見つけたのですが、まだどれもうまくいきません。文字列を整数に変換したいのですが、ASCIIコードのことではありません。
簡単に説明しますと、ある方程式が文字列として渡されます。それを分解し、正しくフォーマットして、一次方程式を解かなければなりません。そうは言っても、文字列をint型に変換することはできません。
文字列が(-5)や(25)などのフォーマットになることはわかっているので、それは間違いなくint型です。しかし、文字列からどうやってそれを取り出すのでしょうか?
私が考えているのは、文字列をfor/whileループで走らせて、数字をチェックし、その後のすべての数字を抽出して、先頭に '-'があるかどうかを確認し、あればintを-1倍するという方法です。
こんなに小さな問題なのに、ちょっと複雑すぎるような気がします。何かアイデアはありませんか?
C++11 では、std::string
から数値型への変換関数が新しく追加されました。
そのため
atoi( str.c_str() )
使える
std::stoi( str )
ここで str
は std::string
としての数値です。
あらゆる種類の数値に対応するバージョンがある。
long stol(string),
float stof(string),
double stod(string)`, ...
参照 [http://en.cppreference.com/w/cpp/string/basic_string/stol][1]
[1]: http://en.cppreference.com/w/cpp/string/basic_string/stol
atoi関数を使って文字列を整数に変換します。
string a = "25";
int b = atoi(a.c_str());
[http://www.cplusplus.com/reference/clibrary/cstdlib/atoi/][1]
[1]: http://www.cplusplus.com/reference/clibrary/cstdlib/atoi/
可能なオプションは以下の通りです。
最初のオプション: sscanf() 。
#include <cstdio>
#include <string>
int i;
float f;
double d;
std::string str;
// string -> integer
if(sscanf(str.c_str(), "%d", &i) != 1)
// error management
// string -> float
if(sscanf(str.c_str(), "%f", &f) != 1)
// error management
// string -> double
if(sscanf(str.c_str(), "%lf", &d) != 1)
// error management
これは、フィールド幅の制限のない "scanf は、libc" のいくつかのバージョンでは、巨大な入力データでクラッシュする可能性があるため、エラーです (cppcheck でも表示されます)。
*2. 2番目のオプション。 std::sto()*2.
#include <iostream>
#include <string>
int i;
float f;
double d;
std::string str;
try {
// string -> integer
int i = std::stoi(s);
// string -> float
float f = std::stof(s);
// string -> double
double d = std::stod(s);
} catch (...) {
// error management
}
このソリューションは短くてエレガントですが、C++11に準拠したコンパイラでのみ利用可能です。
3番目のオプション: sstreams。
#include <string>
#include <sstream>
int i;
float f;
double d;
std::string str;
// string -> integer
std::istringstream ( str ) >> i;
// string -> float
std::istringstream ( str ) >> f;
// string -> double
std::istringstream ( str ) >> d;
// error management ??
しかし、この解決策では、悪い入力を区別することは難しい([こちら][3]参照)。
4. 第四の選択肢。 Boostのlexical_castを使用する。
#include <boost/lexical_cast.hpp>
#include <string>
std::string str;
try {
int i = boost::lexical_cast<int>( str.c_str());
float f = boost::lexical_cast<int>( str.c_str());
double d = boost::lexical_cast<int>( str.c_str());
} catch( boost::bad_lexical_cast const& ) {
// Error management
}
しかし、これは sstream のラッパーに過ぎず、ドキュメントでは、より良いエラー管理のために sstrem を使うことを提案しています (こちら][3] を参照してください)。
5番目のオプション: strto*() 。
この解決策は,エラー管理の関係で非常に長いので,ここに記述します. どの関数もプレーンなintを返すわけではないので,整数の場合は変換が必要になります(この変換を実現する方法については[こちら][4]を参照してください).
**6.第6の選択肢:Qt***.
#include <QString>
#include <string>
bool ok;
std::string;
int i = QString::fromStdString(str).toInt(&ok);
if (!ok)
// Error management
float f = QString::fromStdString(str).toFloat(&ok);
if (!ok)
// Error management
double d = QString::fromStdString(str).toDouble(&ok);
if (!ok)
// Error management
**結論
まとめると、最良の解決策は C++11 の std::stoi() か、第二の選択肢として Qt のライブラリを使用することです。 他のすべての解決策はお勧めできませんし,バグもあります.
[1]: https://stackoverflow.com/questions/9292861/how-could-reading-numbers-using-sscanf-crash [2]: https://stackoverflow.com/questions/7022468/scanf-cppcheck-warning [3]: https://stackoverflow.com/questions/194465/how-to-parse-a-string-to-an-int-in-c [4]: https://stackoverflow.com/questions/2425759/do-i-need-to-cast-the-result-of-strtol-to-int
Boost.Lexical_cast](http://www.boost.org/doc/libs/release/doc/html/boost_lexical_cast.html)はどうでしょうか?
以下がその例です。
gt. 以下の例では、コマンドライン引数を数値データの羅列として扱います。
int main(int argc, char * argv[])
{
using boost::lexical_cast;
using boost::bad_lexical_cast;
std::vector<short> args;
while(*++argv)
{
try
{
args.push_back(lexical_cast<short>(*argv));
}
catch(bad_lexical_cast &)
{
args.push_back(0);
}
}
...
}
確かに、私の解決策は負の整数に対しては動作しませんが、整数を含む入力テキストからすべての正の整数を抽出します。
これは numeric_only
ロケールを利用しています。
int main() {
int num;
std::cin.imbue(std::locale(std::locale(), new numeric_only()));
while ( std::cin >> num)
std::cout << num << std::endl;
return 0;
}
テキストを入力します。
the format (-5) or (25) etc... some text.. and then.. 7987...78hjh.hhjg9878
整数を出力します。
5
25
7987
78
9878
クラス numeric_only
は以下のように定義されています。
struct numeric_only: std::ctype<char>
{
numeric_only(): std::ctype<char>(get_table()) {}
static std::ctype_base::mask const* get_table()
{
static std::vector<std::ctype_base::mask>
rc(std::ctype<char>::table_size,std::ctype_base::space);
std::fill(&rc['0'], &rc[':'], std::ctype_base::digit);
return &rc[0];
}
};
完全なオンラインデモ。 http://ideone.com/dRWSj
ちょっとやりすぎかもしれませんが
boost::lexical_cast<int>( theString )
は、ジョブに
なかなかいいですね。
http://www.cplusplus.com/reference/string/stoi/ より
// stoi example
#include <iostream> // std::cout
#include <string> // std::string, std::stoi
int main ()
{
std::string str_dec = "2001, A Space Odyssey";
std::string str_hex = "40c3";
std::string str_bin = "-10010110001";
std::string str_auto = "0x7f";
std::string::size_type sz; // alias of size_t
int i_dec = std::stoi (str_dec,&sz);
int i_hex = std::stoi (str_hex,nullptr,16);
int i_bin = std::stoi (str_bin,nullptr,2);
int i_auto = std::stoi (str_auto,nullptr,0);
std::cout << str_dec << ": " << i_dec << " and [" << str_dec.substr(sz) << "]\n";
std::cout << str_hex << ": " << i_hex << '\n';
std::cout << str_bin << ": " << i_bin << '\n';
std::cout << str_auto << ": " << i_auto << '\n';
return 0;
}
アウトプット。
2001年、[, A スペースオデッセイ 2001年と[, A Space Odyssey]
40c3: 16579
-10010110001: -1201
0x7f: 127
Windowsでは
const std::wstring hex = L"0x13";
const std::wstring dec = L"19";
int ret;
if (StrToIntEx(hex.c_str(), STIF_SUPPORT_HEX, &ret)) {
std::cout << ret << "\n";
}
if (StrToIntEx(dec.c_str(), STIF_SUPPORT_HEX, &ret)) {
std::cout << ret << "\n";
}
16進数を解釈する必要がある場合は、strtol
, stringstream
に基底値を指定する必要がある。
たくさんの答えがあり、たくさんの可能性があります。 ここで足りないのは、文字列を異なるC++の積分型(short, int, long, bool, ...)に変換する普遍的なメソッドです。 私は次のような解決策を思いつきました。
#include<sstream>
#include<exception>
#include<string>
#include<type_traits>
using namespace std;
template<typename T>
T toIntegralType(const string &str) {
static_assert(is_integral<T>::value, "Integral type required.");
T ret;
stringstream ss(str);
ss >> ret;
if ( to_string(ret) != str)
throw invalid_argument("Can't convert " + str);
return ret;
}
使用例を紹介します。
string str = "123";
int x = toIntegralType<int>(str); // x = 123
str = "123a";
x = toIntegralType<int>(str); // throws exception, because "123a" is not int
str = "1";
bool y = toIntegralType<bool>(str); // y is true
str = "0";
y = toIntegralType<bool>(str); // y is false
str = "00";
y = toIntegralType<bool>(str); // throws exception
文字列を積分型に変換するには、文字列ストリーム出力演算子を使用すればよいのではないでしょうか? これがその答えです。 例えば、文字列に積分型の上限を超える値が含まれていたとします。 例えば、Wndows 64では最大intは2147483647です。 文字列にmax int + 1を代入してみましょう。 string str = "2147483648" となります。 さて、この文字列をintに変換すると
stringstream ss(str);
int x;
ss >> x;
xが2147483647になると、何が間違いなくエラーになります。 文字列 "2147483648". が int 2147483647 に変換されるはずがありませんでした。 提供されている関数 toIntegralType は、このようなエラーを検出して例外をスローします。
一行バージョン。
一行バージョン: long n = strtol(s.c_str(), NULL, base);
.
(s
は文字列、base
は 2, 8, 10, 16 などの int
です) .
strtol` の詳細は このリンク を参照してください。
中心となるのは、cstdlib
に含まれる strtol
関数を利用することである。
strtolは
char配列しか扱えないので、
stringを
char` 配列に変換する必要がある。
このリンク](https://stackoverflow.com/a/13294114/8328786)を参照するとよい。
例としては、以下のようになります。
#include <iostream>
#include <string> // string type
#include <bitset> // bitset type used in the output
int main(){
s = "1111000001011010";
long t = strtol(s.c_str(), NULL, 2); // 2 is the base which parse the string
cout << s << endl;
cout << t << endl;
cout << hex << t << endl;
cout << bitset<16> (t) << endl;
return 0;
}
を出力します。
1111000001011010
61530
f05a
1111000001011010