351

次の (Python 疑似コード) を C++ で実装するにはどうすればよいですか?

if argv[1].startswith('--foo='):
    foo_value = int(argv[1][len('--foo='):])

(たとえば、 が の場合、argv[1]はです。)--foo=98foo_value98

更新:単純な小さなコマンド ライン ツールに非常に小さな変更を加えることを考えているだけなので、Boost を調べるのをためらっています (マイナーなリンクを作成して Boost を使用する方法を学ぶ必要はありません)。変化する)。

4

23 に答える 23

694

rfind検索位置パラメーターを受け取るオーバーロードを使用しpos、ゼロを渡します。

std::string s = "tititoto";
if (s.rfind("titi", 0) == 0) { // pos=0 limits the search to the prefix
  // s starts with prefix
}

他に誰が必要ですか?ピュアSTL!

多くの人がこれを「プレフィックスを探して文字列全体を逆方向に検索する」という意味に誤解しています。それは間違った結果をもたらし (たとえば、string("tititito").rfind("titi")2 を返すため、比較すると== 0false が返されます)、非効率的です (先頭だけではなく文字列全体を調べます)。posしかし、パラメータを as として渡し0、検索をその位置またはそれ以前の一致のみに制限するため、それは行われません。例えば:

std::string test = "0123123";
size_t match1 = test.rfind("123");    // returns 4 (rightmost match)
size_t match2 = test.rfind("123", 2); // returns 1 (skipped over later match)
size_t match3 = test.rfind("123", 0); // returns std::string::npos (i.e. not found)
于 2016-11-05T17:36:08.503 に答える
203

次のようにします。

std::string prefix("--foo=");
if (!arg.compare(0, prefix.size(), prefix))
    foo_value = std::stoi(arg.substr(prefix.size()));

これを行うBoost.ProgramOptionsなどのライブラリを探すことも良い考えです。

于 2009-12-10T01:07:31.337 に答える
163

完全を期すために、C の方法について説明します。

strが元substrの文字列で、がチェックしたい部分文字列である場合、

strncmp(str, substr, strlen(substr))

で始まる0場合に返されます。関数とは C ヘッダー ファイルにあります。strsubstrstrncmpstrlen<string.h>

(Yaseen Rauf が最初に投稿したものはここにあり、マークアップが追加されています)

大文字と小文字を区別しない比較では、strnicmp代わりに を使用しstrncmpます。

これは C の方法です。C++ 文字列の場合、次のように同じ関数を使用できます。

strncmp(str.c_str(), substr.c_str(), substr.size())
于 2011-08-22T02:58:31.363 に答える
93

すでにブーストを使用している場合は、ブースト文字列アルゴリズム+ブースト字句キャストを使用して実行できます。

#include <boost/algorithm/string/predicate.hpp>
#include <boost/lexical_cast.hpp>

try {    
    if (boost::starts_with(argv[1], "--foo="))
        foo_value = boost::lexical_cast<int>(argv[1]+6);
} catch (boost::bad_lexical_cast) {
    // bad parameter
}

この種のアプローチは、ここで提供される他の多くの回答と同様に、非常に単純なタスクには問題ありませんが、長期的には、通常、コマンド ライン解析ライブラリを使用する方が適切です。Boost には 1 つ ( Boost.Program_options ) があり、たまたま Boost を既に使用している場合は意味があるかもしれません。

それ以外の場合は、「c++ コマンド ライン パーサー」を検索すると、いくつかのオプションが表示されます。

于 2009-12-10T01:03:41.690 に答える
88

私が自分で使用するコード:

std::string prefix = "-param=";
std::string argument = argv[1];
if(argument.substr(0, prefix.size()) == prefix) {
    std::string argumentValue = argument.substr(prefix.size());
}
于 2011-12-29T19:41:26.970 に答える
53

STLアルゴリズム/不一致機能はまだ誰も使用していません。これが true を返す場合、プレフィックスは「toCheck」のプレフィックスです。

std::mismatch(prefix.begin(), prefix.end(), toCheck.begin()).first == prefix.end()

完全なサンプル プログラム:

#include <algorithm>
#include <string>
#include <iostream>

int main(int argc, char** argv) {
    if (argc != 3) {
        std::cerr << "Usage: " << argv[0] << " prefix string" << std::endl
                  << "Will print true if 'prefix' is a prefix of string" << std::endl;
        return -1;
    }
    std::string prefix(argv[1]);
    std::string toCheck(argv[2]);
    if (prefix.length() > toCheck.length()) {
        std::cerr << "Usage: " << argv[0] << " prefix string" << std::endl
                  << "'prefix' is longer than 'string'" <<  std::endl;
        return 2;
    }
    if (std::mismatch(prefix.begin(), prefix.end(), toCheck.begin()).first == prefix.end()) {
        std::cout << '"' << prefix << '"' << " is a prefix of " << '"' << toCheck << '"' << std::endl;
        return 0;
    } else {
        std::cout << '"' << prefix << '"' << " is NOT a prefix of " << '"' << toCheck << '"' << std::endl;
        return 1;
    }
}

編集:

@James T. Huggett が示唆するように、std::equal は次の質問により適しています: A は B のプレフィックスですか? 少し短いコードです:

std::equal(prefix.begin(), prefix.end(), toCheck.begin())

完全なサンプル プログラム:

#include <algorithm>
#include <string>
#include <iostream>

int main(int argc, char **argv) {
  if (argc != 3) {
    std::cerr << "Usage: " << argv[0] << " prefix string" << std::endl
              << "Will print true if 'prefix' is a prefix of string"
              << std::endl;
    return -1;
  }
  std::string prefix(argv[1]);
  std::string toCheck(argv[2]);
  if (prefix.length() > toCheck.length()) {
    std::cerr << "Usage: " << argv[0] << " prefix string" << std::endl
              << "'prefix' is longer than 'string'" << std::endl;
    return 2;
  }
  if (std::equal(prefix.begin(), prefix.end(), toCheck.begin())) {
    std::cout << '"' << prefix << '"' << " is a prefix of " << '"' << toCheck
              << '"' << std::endl;
    return 0;
  } else {
    std::cout << '"' << prefix << '"' << " is NOT a prefix of " << '"'
              << toCheck << '"' << std::endl;
    return 1;
  }
}
于 2013-01-13T00:09:43.623 に答える
12

STL を使用すると、次のようになります。

std::string prefix = "--foo=";
std::string arg = argv[1];
if (prefix.size()<=arg.size() && std::equal(prefix.begin(), prefix.end(), arg.begin())) {
  std::istringstream iss(arg.substr(prefix.size()));
  iss >> foo_value;
}
于 2011-12-21T21:56:25.383 に答える
11

sscanfC コンストラクトを使用すると炎上するリスクがありますが、この例はほとんどの Boost ソリューションよりも洗練されていると思います。また、Python インタープリターがある場所で実行している場合は、リンケージについて心配する必要はありません!

#include <stdio.h>
#include <string.h>

int main(int argc, char **argv)
{
    for (int i = 1; i != argc; ++i) {
        int number = 0;
        int size = 0;
        sscanf(argv[i], "--foo=%d%n", &number, &size);
        if (size == strlen(argv[i])) {
            printf("number: %d\n", number);
        }
        else {
            printf("not-a-number\n");
        }
    }
    return 0;
}

これは、ソリューションが先頭/末尾のガベージを同等の Python コードと同じくらい正確に処理し、何よりも正確に処理することを示す出力例ですatoi(数値以外の接尾辞を誤って無視します)。

$ ./scan --foo=2 --foo=2d --foo='2 ' ' --foo=2'
number: 2
not-a-number
not-a-number
not-a-number
于 2009-12-10T03:29:00.327 に答える
6

C++11 との互換性が必要で、boost を使用できない場合は、boost 互換のドロップインと使用例を以下に示します。

#include <iostream>
#include <string>

static bool starts_with(const std::string str, const std::string prefix)
{
    return ((prefix.size() <= str.size()) && std::equal(prefix.begin(), prefix.end(), str.begin()));
}

int main(int argc, char* argv[])
{
    bool usage = false;
    unsigned int foos = 0; // default number of foos if no parameter was supplied

    if (argc > 1)
    {
        const std::string fParamPrefix = "-f="; // shorthand for foo
        const std::string fooParamPrefix = "--foo=";

        for (unsigned int i = 1; i < argc; ++i)
        {
            const std::string arg = argv[i];

            try
            {
                if ((arg == "-h") || (arg == "--help"))
                {
                    usage = true;
                } else if (starts_with(arg, fParamPrefix)) {
                    foos = std::stoul(arg.substr(fParamPrefix.size()));
                } else if (starts_with(arg, fooParamPrefix)) {
                    foos = std::stoul(arg.substr(fooParamPrefix.size()));
                }
            } catch (std::exception& e) {
                std::cerr << "Invalid parameter: " << argv[i] << std::endl << std::endl;
                usage = true;
            }
        }
    }

    if (usage)
    {
        std::cerr << "Usage: " << argv[0] << " [OPTION]..." << std::endl;
        std::cerr << "Example program for parameter parsing." << std::endl << std::endl;
        std::cerr << "  -f, --foo=N   use N foos (optional)" << std::endl;
        return 1;
    }

    std::cerr << "number of foos given: " << foos << std::endl;
}
于 2018-11-16T15:51:33.953 に答える
5

gnu getopts を使用しないのはなぜですか? 以下は基本的な例です (安全チェックなし):

#include <getopt.h>
#include <stdio.h>

int main(int argc, char** argv)
{
  option long_options[] = {
    {"foo", required_argument, 0, 0},
    {0,0,0,0}
  };

  getopt_long(argc, argv, "f:", long_options, 0);

  printf("%s\n", optarg);
}

次のコマンドの場合:

$ ./a.out --foo=33

あなたは得るでしょう

33
于 2013-06-11T12:08:06.383 に答える
3

ライブラリなどの複雑な使用はなぜですか?C++ String オブジェクトは [] 演算子をオーバーロードするため、char を比較するだけで済みます。ディレクトリ内のすべてのファイルを一覧表示し、非表示のファイルと .. および .. 疑似ファイル。

while ((ep = readdir(dp)))
{
    string s(ep->d_name);
    if (!(s[0] == '.')) // Omit invisible files and .. or .
        files.push_back(s);
}

それはとても簡単です..

于 2011-02-15T11:56:01.620 に答える
2

次のものも使用できますstrstr

if (strstr(str, substr) == substr) {
    // 'str' starts with 'substr'
}

しかし、文字列が実際に「substr」で始まらない場合、文字列全体をループする必要があるため、短い文字列にのみ適していると思います。

于 2012-08-26T23:41:24.090 に答える
-4
if(boost::starts_with(string_to_search, string_to_look_for))
    intval = boost::lexical_cast<int>(string_to_search.substr(string_to_look_for.length()));

これは完全にテストされていません。原理は Python のものと同じです。Boost.StringAlgo と Boost.LexicalCast が必要です。

文字列が他の文字列で始まるかどうかを確認し、最初の文字列の部分文字列 ('slice') を取得し、字句キャストを使用して変換します。

于 2009-12-10T01:08:15.283 に答える