0

私たちは皆、文字列から数値に変換する方法を知っています。

int str2num(const string& str) 
{
   stringstream is(str);
   int result;
   return is >> result ? result : 0;
};

私の質問は、文字列を数値に変換できないが0ではない場合を区別できるようにしたいです。例:

1.) "0" => 0
2.) "0dasd" => 0
3.) "" => 0
4.) "some string" => 0 but true
5.) "345" => 345

ケース(4)を検出できるようにしたい。私が持っている唯一のアイデアは、文字列!! .find()か何かを検索することです。stringstreamには、この状況を示す何らかの方法がありますか?


編集:いくつかの説明:num2str()会話が失敗したり戻ったりしたときに私が大丈夫な関数として、関数はie0にもなります。しかし、では、関数内でそれを検出できるようにしたいので、あなたが言ったように...をスローするか、pair<>またはout-variableを使用して帯域外データを返します。return 0(cases:1,2,3,4)case 4err

または、さらに明確にするために、私は検出したい:

それis >> num returns 0 (ex:"0","0.0","000", "0sad","asd0ss")が本当にゼロであるか、それが数値に変換できない文字列であるかどうかIEは0文字列と非0文字列を区別します

PS>変換時に0-in-a-stringのどのケースが0-numまたはjust-stringとして解釈されるかわからないため、おそらく混乱も生じます。私はさらに混乱しましたか:)またはそれは今より明確になっていますか?Perlのゼロだが真のセマンティクスに沿って何かを実装したい。


EDIT2:範囲外のデータを正確に返す方法のすべての例をありがとう、本当に感謝しています..つまり本当に..(おそらくペア<>を使用しますが、ブーストやC++11セマンティクスはまだ使用しません)。しかし、私は「ストリングストリームとは何か、そしてその違いをどのように検出するか」にもっと興味があり0-stringましnon-0-stringた。

4

5 に答える 5

2

何かを正常に変換したかどうかをテストするのは非常に簡単です。ただし、3番目と4番目のケースを区別するのは少し難しくなります。「変換する入力がない」を「正常に変換されたもの」として扱うことは、(私には)あまり意味がないようです。ケース3と4を失敗した変換として扱い、残りを成功したものとして扱うことができれば、それは非常に簡単です。変換を試みた後、ストリームの状態をテストするだけです。

#include <sstream>
#include <string>
#include <iostream>

int main(){ 
    char const *inputs[] = { "0", "0dasd", "", "some string", "345"};

    for (int i=0; i<5; i++) {
        std::istringstream buf(inputs[i]);
        int val;

        if (buf>>val) 
            std::cout << "Converted : \"" << inputs[i] << "\" To: " << val << "\n";
        else
            std::cout << "Could not convert: \"" << inputs[i] << "\" To int\n";
    }
    return 0;
}

生成するもの:

Converted : "0" To: 0
Converted : "0dasd" To: 0
Could not convert: "" To int
Could not convert: "some string" To int
Converted : "345" To: 345

ケース3も同様に成功したものとして扱いたい場合は、空の文字列に特別な扱いを追加しても、常に正常に変換されるので、それほど多くはかからないと思います。

于 2012-09-15T22:25:21.910 に答える
2

文字列変換機能が悪いので、気分が悪くなるはずです。

template<typename F> int str2num(const string& str, F&& f) {
   stringstream is(str);
   int result;
   if (is >> result) return result;
   return f();
}
int str2num(const string& str) {
    return str2num(str, [] -> int {
        throw std::runtime_error("Parse failure!");
    });
}
int str2num(const string& str, int def) {
    return str2num(str, [=] {
        return def;
    });
}

魔法のデフォルト値として0を選択するのは悪いことです。おそらく、整数を解析しようとする人にとっては32が適切なデフォルトです。0は、解析の失敗とは別の意味のある値である可能性もあります。デフォルトが必要な場合は、ユーザーが明示的に指定する必要があります。これは、ランダムI / O関数が、意味のあるデフォルトが何であるかを認識していないためです

ユーザーがエラー処理関数または意味のあるデフォルト値のいずれかの形式で明示的なエラー処理戦略を提供しない場合は、例外をスローすることが唯一の方法です。

于 2012-09-15T23:16:22.883 に答える
1

2 ビットの情報を返す必要があります。1 つは変換結果の整数、もう 1 つは成功かどうかを示すフラグです。エラー条件は、例外をスローすることによって処理することもできますが、通常、外部データは決して「例外的」ではなく、解析エラーは例外ではなく通常の制御フローとして処理する必要があります。

結果は次のようになります。

template <typename T>
boost::optional<int> parse_as(std::string const & s)
{
    if (s.empty()) { return T(); }

    T result;

    return std::istringstream(s) >> result ? result : boost::none;
}

使用法: auto n = parse_as<int>(str);、結果が設定されているかどうかをテストします。


文字列全体が一致する必要がある代替トークン抽出:

std::istringstream iss(s);

return iss >> result >> std::ws && iss.get() == EOF ? result : boost::none;
于 2012-09-15T23:23:21.973 に答える
0

結果をどのように通知するかが明確ではありません。抽出関数は、変換に失敗した場合、ストリームを不良状態に設定します。数字を削除できなかった場合、整数の変換は失敗します。つまり、次の3つのケースがあるようです。

  1. 文字列はempty()であり、を返し0ます。
  2. 変換は成功し、値を返します。
  3. 変換が失敗し、失敗を示すために何かを実行します。たとえば、例外をスローします。
于 2012-09-15T22:27:13.447 に答える
0

コメントしてくれたすべての人に感謝します。これが私が考えていたことです:

#include <iostream>
#include <string>
#include <sstream>
#include <assert.h>
using namespace std;
#define pBool std::pair<bool,int>

pBool str2num(const string& str) {
    istringstream is(str);
    pBool rv(false,0);
    if (str == "0E0") {//Zero but true
        rv = std::make_pair(true,0);
    } else {
        is >> rv.second;//convert
        //cout << "fail?:" << is.fail() << endl;
        //logical XOR : !fail != !0?
        if ( !is.fail() != (rv.second == 0) ) rv.first = true;
//      if (!is.fail() && rv.second != 0) rv.first = true;//successful conversion
//      if (is.fail() && rv.second == 0) rv.first = true;
    };
    return rv;
};

template<class T>
void dump_pair(T& p) {
    cout << "Bool:" << p.first << endl;
    cout << "Val :" << p.second << endl;
}

int main() {

    cout << ">>0E0" << endl;
    pBool rv1 = str2num("0E0");
    dump_pair(rv1);

    cout << ">>0" << endl;
    pBool rv2 = str2num("0");
    dump_pair(rv2);

    cout << ">>0.0dsad" << endl;
    pBool rv3 = str2num("0dsad");
    dump_pair(rv3);

    cout << ">>456ttt" << endl;
    pBool rv4 = str2num("456ttt");
    dump_pair(rv4);

    cout << ">>adttt" << endl;
    pBool rv5 = str2num("ad555ttt");
    dump_pair(rv5);

    return 0;
}

====OUTPUT====
>>0E0
Bool:1
Val :0
>>0
Bool:0
Val :0
>>0.0dsad
Bool:0
Val :0
>>456ttt
Bool:1
Val :456
>>adttt
Bool:1
Val :0
于 2012-09-16T07:24:37.980 に答える