web-dev-qa-db-ja.com

C ++のstd :: stringが特定の文字列で始まっているかどうかを確認し、部分文字列をintに変換するにはどうすればよいですか?

C++で次の(Python疑似コード)を実装する方法

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

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

更新:単純な小さなコマンドラインツールにごくわずかな変更を加えることを検討しているだけなので、Boostを検討することを躊躇しています(リンクする方法を学ぶ必要はありません)。マイナーチェンジのためにBoostを使ってください)。

191
Daryl Spitzer

すでにBoostを使っているのであれば、 boost文字列アルゴリズム + boost lexical cast: でそれを行うことができます。

#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 ++ command line parser"を検索すると多くのオプションが得られます。

84
Ferruccio
std::string s = "tititoto";
if (s.rfind("titi", 0) == 0) {
  // s starts with prefix
}

他に何か必要な人は?純粋なSTL!

249
user3046585

あなたはこのようにするでしょう:

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

Boost.ProgramOptionsのようにあなたのためにこれをするライブラリを探すのも良い考えです。

177
Thomas

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

strが元の文字列の場合、substrが確認したい部分文字列です。

strncmp(str, substr, strlen(substr))

strsubstrで始まる場合、0を返します。関数strncmpおよびstrlenは、Cヘッダーファイル<string.h>にあります。

(もともとYaseen Raufによって投稿されました ここ 、マークアップが追加されました)

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

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

strncmp(str.c_str(), substr.c_str(), substr.size())
133
Felix Dombek

私が自分で使うコード:

std::string prefix = "-param=";
std::string argument = argv[1];
if(argument.substr(0, prefix.size()) == prefix) {
    std::string argumentValue = argument.substr(prefix.size());
}
78

誰もSTL algorithm/mismatch 関数を使っていません。これがtrueを返す場合、prefixは 'toCheck'のプレフィックスです。

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

Progの完全な例

#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())

Progの完全な例

#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;
  }
}
44
matiu

argv[1]"--foo"の両方の文字列がCの文字列であることを考えると、 @ FelixDombek's answer が一番下の解決策です。

しかし、他の答えを見てみると、あなたのテキストがすでにstd::stringとして利用可能であるならば、これまで言及されていなかった簡単でゼロコピーの最大効率的な解決策が存在することは注目に値すると思いました。

const char * foo = "--foo";
if (text.rfind(foo, 0) == 0)
    foo_value = text.substr(strlen(foo));

そしてfooが既に文字列であるならば:

std::string foo("--foo");
if (text.rfind(foo, 0) == 0)
    foo_value = text.substr(foo.length());
23
Marcelo Cantos

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;
}
11
razvanco13
text.substr(0, start.length()) == start
8
Macsinus

Cの構文を使うことに批判される危険性があるので、このsscanfの例は、ほとんどの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
8
Tom

C++ 17では std::basic_string_view &C++ 20では std::basic_string::starts_with または std::basic_string_view::starts_with を使用できます。

std::string_viewと比較したstd::stringの利点 - メモリ管理に関して - は、それが "文字列"(charのようなオブジェクトの連続したシーケンス)へのポインタを保持するだけで、そのサイズを知っているということです。整数値を取得するためだけにソース文字列を移動/コピーしない例

#include <string_view>
#include <exception>
#include <iostream>

const char * argument = "--foo=42"; // Emulating command argument.
const char * argumentPrefix = "--foo";
int inputValue = 0;

std::string_view argView = argument;
if (argView.starts_with(argumentPrefix))
{
    std::string_view prefixView = argumentPrefix; // Helper for getting the size of argumentPrefix.
    try
    {
        // The underlying data of argView is nul-terminated, therefore we can use data().
        inputValue = std::atoi(argView.substr(prefixView.size() + 1).data());
    }
    catch (std::exception& e)
    {
        std::cerr << e.what();
    }
}
8
Roi Danton

以下のようにユーティリティメソッドにラップされたstd::string::compareを使用します。

static bool startsWith(const string& s, const string& prefix) {
    return s.size() >= prefix.size() && s.compare(0, prefix.size(), prefix) == 0;
}
7
Shital Shah

なぜ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
5
Carl Cook

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;
}
3
vallismortis

strstrを使用することもできます。

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

しかし、文字列が実際に 'substr'で始まっていない場合は文字列全体をループ処理しなければならないので、短い文字列だけに適していると思います。

2
szx
std::string text = "--foo=98";
std::string start = "--foo=";

if (text.find(start) == 0)
{
    int n = stoi(text.substr(start.length()));
    std::cout << n << std::endl;
}
1
mois

さて、なぜライブラリやものを複雑に使うのでしょうか。 C++のStringオブジェクトは[]演算子をオーバーロードしているので、charを比較することができます。ディレクトリ内のすべてのファイルを一覧表示し、見えないファイルと..とを無視したいので。疑似ファイル.

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

それはとても簡単です。

1
Nils

C++ 11以降では std :: regex_search も使用できます。次のようになります(失敗した場合は空の文字列を返します)。

#include <regex>

std::string startsWith(const std::string &str, const std::string &prefix) {
  std::smatch match;
  std::regex_search(str, match, std::regex("^" + prefix));
  return match.suffix();
}
1
alextoind

C++ 11以降ではfind()find_first_of()を使うことができます。

Findを使って単一の文字を探す例:

#include <string>
std::string name = "Aaah";
size_t found_index = name.find('a');
if (found_index != std::string::npos) {
    // Found string containing 'a'
}

Findを使用して5桁目から始まる完全な文字列&を検索する例:

std::string name = "Aaah";
size_t found_index = name.find('h', 3);
if (found_index != std::string::npos) {
    // Found string containing 'h'
}

先頭のみを検索するためにfind_first_of()と最初の文字だけを使用した例:

std::string name = ".hidden._di.r";
size_t found_index = name.find_first_of('.');
if (found_index == 0) {
    // Found '.' at first position in string
}

がんばろう!

0
danger89