2

「1.0.0」という文字列があり、「1」、「0」、および「0」を抽出したいと考えています。最後のゼロが存在しない場合、文字列はデフォルトで 0 を格納する必要があります。

verstr.substr(0,verstr.find(".");

上記のステートメントは「1」である最初の数字を見つけることができますが、文字列の残りを抽出するための解決策を考えることができません。

この後、次のように long に変換します。

        va = atol(verstr.substr(0,verstr.find(".")).c_str());

だから私は va に "1" 、 "vb" に 0 などを入れたい

ありがとう。

4

7 に答える 7

4

C++11 ソリューション:

#include <iostream>
#include <string>
#include <regex>

using namespace std;

int main(int, char **) {
    string version("1.2.3");
    match_results<string::const_iterator> m;
    regex re("([0-9]+)\\.([0-9]+)(\\.([0-9]+))?");
    if (regex_match(version, m, re)) {
        int major = stoi(m[1].str()),
            minor = stoi(m[2].str()),
            rev = stoi(m[4].str().length() == 0 ? 0 : m[4].str());
        cout << "major: " << major << endl;
        cout << "minor: " << minor << endl;
        cout << "rev: " << rev << endl;
    } else {
        cout << "no match\n";
    }
}

使用される正規表現は([0-9]+)\.([0-9]+)(\.([0-9]+))?次のとおりです。

[0-9]+1 つ以上の数字に一致

\.リテラルのドットに一致します。

?最後の式に続くのは、それがオプションであることを示します

とで囲まれた式は()キャプチャ グループです。この式には 5 つのキャプチャ グループがあります。

0 - 常に文字列全体に一致します。これは使用しません。

1 - メジャー バージョン番号と一致します。

2 - マイナー バージョン番号と一致します。

3 - リビジョン番号が続くドットに一致します。これは使用しませんが、括弧の後に a を使用?してこのグループ全体をオプションにするために必要です。

4 - リビジョン番号に一致します。

于 2012-08-01T13:40:14.460 に答える
3

を使用する可能性がありますstd::sscanf()。使い方は簡単で、比較的数行のコードで一定レベルのエラーチェックを提供します。

#include <iostream>
#include <string>
#include <cstdio>

int main()
{
    std::string input[] = { "1.0.7", "1.0.", "1.0", "1.", "1" };

    for (size_t i = 0; i < sizeof(input)/sizeof(input[0]); i++)
    {
        std::cout << input[i] << ": ";

        // Init to zero.
        int parts[3] = { 0 };

        // sscanf() returns number of assignments made.
        if (std::sscanf(input[i].c_str(),
                        "%d.%d.%d",
                        &parts[0],
                        &parts[1],
                        &parts[2]) >= 2)
        {
            // OK, the string contained at least two digits.
            std::cout << parts[0]
                      << ","
                      << parts[1]
                      << ","
                      << parts[2]
                      << "\n";
        }
        else
        {
            std::cout << "bad format\n";
        }
    }
    return 0;
}

出力:

1.0.7:1,0,7
1.0 .: 1,0,0
1.0:1,0,0
1.:フォーマットが悪い
1:フォーマットが悪い

オンラインデモを参照してください:http://ideone.com/0Ox9b

于 2012-08-01T13:29:08.840 に答える
3

必要なものを理解しているかどうかわかりません。数字を文字列として取得したい場合は、最小 x 桁で、次のようなことができます。

vector<string> GetVersion(const string &strInput, int iMinSize)
{
    vector<string> vRetValue;

    std::stringstream ss(strInput); 
    string strItem;
    while(std::getline(ss, strItem, '.'))   
        vRetValue.push_back(strItem);

    while(vRetValue.size() < iMinSize)
        vRetValue.push_back("0");

    return vRetValue;
}

int _tmain(int argc, _TCHAR* argv[])
{   
    vector<string> vRetValue = GetVersion("1.0", 3); 
    return 0;
}
于 2012-08-01T13:27:20.820 に答える
2

findそしてsubstr、特に構文チェックを緩める必要がある場合に、多くの単純な構文解析の問題に非常に適した2つの非常に優れた関数オーバーロードのファミリーです。

バージョンベクトルから複数のスカラーを抽出するには、見つかったインデックスを次の場所に保存します。

const auto a = verstr.find('.');
const std::string major = verstr.substr(0, a);

次に、のオーバーロードの1つで再利用し、次のいずれstring::findかで検索を開始しaます。

const auto b = verstr.find ('.', a+1);
const std::string minor = verstr.substr(a+1, b);

などなど。

構文チェックが必要な場合は、返されたインデックスを以下と比較してくださいstring::npos

const auto a = verstr.find('.');
if (std::string::npos == a)
    .... bad syntax ....

この答えのペーストビンスタイルバージョン:

#include <string>
#include <stdexcept>
#include <iostream>

struct Version
{
    std::string Major, Minor, Patch;

    Version(std::string const &Major)
    : Major(Major), Minor("0"), Patch("0")
    {}

    Version(std::string const &Major, std::string const &Minor)
    : Major(Major), Minor(Minor), Patch("0")
    {}

    Version(std::string const &Major, std::string const &Minor, std::string const &Patch)
    : Major(Major), Minor(Minor), Patch(Patch)
    {}
};

std::ostream& operator<< (std::ostream &os, Version const &v)
{
    return os << v.Major << '.' << v.Minor << '.' << v.Patch;
}

Version parse (std::string const &verstr) {
    if (verstr.empty()) throw std::invalid_argument("bad syntax");

    const auto first_dot = verstr.find('.');
    if (first_dot == std::string::npos)
        return Version(verstr);

    const auto second_dot = verstr.find('.', first_dot+1);
    if (second_dot == std::string::npos)
        return Version(verstr.substr(0, first_dot),
                       verstr.substr(first_dot+1, second_dot));


    return Version(verstr.substr(0, first_dot),
                   verstr.substr(first_dot+1, second_dot),
                   verstr.substr(second_dot+1));

}

その後

int main () {
    std::cout << parse("1.0") << '\n'
              << parse("1.0.4+Patches(55,322)") << '\n'
              << parse("1") << '\n';

    parse(""); // expected to throw
}
于 2012-08-01T13:53:17.360 に答える
0

境界線より下の解決策の代わりにこのようなものを試してください

string s = "1.0.0";
string delimiters = ".";
size_t current;
size_t next = -1;
do
{
  current = next + 1;
  next = s.find_first_of( delimiters, current );
  string current_substring = s.substr( current, next - current ); // here you have the substring
}
while (next != string::npos);

@DavidSchwartzとのこの回答の下の議論によると、あなたが本当に何をしているのかわからない場合は、以下のこのソリューションを使用しないでください

関数strtok http://www.cplusplus.com/reference/clibrary/cstring/strtok/を見てください

  char str[] = "1.0.0";
  char * pch;
  pch = strtok (str,".");
  while (pch != NULL)
  {
    printf ("%s\n",pch);
    pch = strtok (NULL, ".");
  }
于 2012-08-01T13:12:58.053 に答える
0

Boost ライブラリ、特にString Algoを見てください。

文字列操作の標準ライブラリ サポートは、C++ では多少制限されています。そして、車輪の再発明はまったく悪いことです。

アップデート:

コメントで、find/substr ベースのソリューションをすべて悪いスタイルだと考える理由を尋ねられました。がんばります。

質問に別段の記載がないため、ここではパフォーマンスは問題ではありません。保守性と可読性ははるかに重要です。ここで提案されているすべてのソリューションは、分割アルゴリズムのセマンティクスを特定のバージョン解析アルゴリズムのセマンティクスと密接に結び付けています。これは両方を傷つけます。

バージョン形式を変更する必要がある場合、分割を実装するコードのまったく同じブロックを変更する必要があり、エラーが発生しやすくなるため、これは保守性を損ないます。同じことが単体テストにも当てはまります。

これは可読性を損ないます。セマンティクスが混在しているため、このコード ブロックの背後にある意図をすぐには推測できないからです。たとえば、欠落している 3D バージョンの引数がどのように処理されるかを確認するために解析アルゴリズムを調べているとき、分割実装の詳細を調べて時間を無駄にしない方がよいでしょう。

パターンの解析がもう少し難しい場合は、正規表現をお勧めします。しかし、この場合、文字列を区切り文字で分割することは一般的なアクションであり、別の関数として使用することを正当化するために十分に使用されることがよくあります。

于 2012-08-01T13:23:51.367 に答える
-1

小さな文字列での単純な文字比較のみの場合...

char[] はそれほど悪くないはずです...そしてC関数は動作するはずです...(編集:一部の人にとっては、それは冒涜です...多くのC++メソッドは、constかどうかにかかわらずchar *を使用します)。

同じ機能を持ち、より多くのメモリを使用し、プロセスに費やす時間を増やすのに、なぜオブジェクトを使用するのでしょうか?

編集:いくつかの答えが多くの文字列オブジェクトを作成することを想定しているのを見ました...それが本当に最善の方法であるかどうかはわかりません...小さな2行の再帰的なCのような関数は、多くの息を切らさずにそれを行うことができます. C ++コードでは、おそらく文字列オブジェクトでそれを行うでしょう.

文字列オブジェクトでは、最初に length プロパティを使用して最後の文字を取得します ([] 演算子または適切なメソッドを使用)。次に、2つの要素を取得する必要があります(ループ内、または正規表現を受け入れるオブジェクトで2つの後方参照を使用する(効率的ではありません))

于 2012-08-01T13:32:56.983 に答える