답변:
다음과 같은 매개 변수 rfind
가 있는 과부하를 사용하십시오 pos
.
std::string s = "tititoto";
if (s.rfind("titi", 0) == 0) {
// s starts with prefix
}
누가 다른 게 필요한가요? 순수한 STL!
많은 사람들이 "접두사를 찾는 전체 문자열을 거꾸로 검색"을 의미한다고 이것을 잘못 읽었습니다. 그것은 잘못된 결과를 줄 것입니다 (예 : string("tititito").rfind("titi")
2를 비교하면 == 0
false를 반환 할 것입니다). 그러나 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)
find
경우 반환 값은 0 만됩니다 . 다른 곳에서 발견되면 0이 아닌 반환 값을 얻을 수 있으며 찾지 못하면 0이 아닌 값을 얻습니다 . 내가 옳다고 가정하면, 비표준 항목을 가져올 필요가 없기 때문에이 대답을 선호합니다 (예, Boost가 어디에나 있다는 것을 알고 있습니다. 단순한 것들에 대해서는 핵심 C ++ 라이브러리를 선호합니다). titi
npos
titi
하지만 변환 부분이 없습니다.
rfind()
는 없습니다 pos
. pos
매개 변수를 사용하는 오버로드를 사용하면 전체 문자열을 검색하지 않고 해당 위치 및 이전 위치 만 검색합니다. ( 매개 변수가있는 regular find()
와 마찬가지로 pos
해당 위치 이상을 찾습니다.) 따라서이 pos == 0
답변에 표시된 것처럼을 전달 하면 문자 그대로 해당 위치에서 일치하는 항목 만 고려합니다. 그것은 이미 답변과 의견 모두에서 설명하고있었습니다.
당신은 이것을 이렇게 할 것입니다 :
std::string prefix("--foo=");
if (!arg.compare(0, prefix.size(), prefix))
foo_value = atoi(arg.substr(prefix.size()).c_str());
이를 위해 Boost.ProgramOptions와 같은 라이브러리를 찾는 것도 좋습니다.
atoi("123xyz")
반환 123
하는 반면 파이썬 int("123xyz")
은 예외를 던집니다.
atoi
와 함께 strtol
또는 strtoll
우리가 입력 값에 오류 조건을 감지 할 수있는.
rfind
작동 최적화에 의존하는 것보다 더 나은 솔루션 입니다.
완전성을 위해 C 방법을 언급 할 것입니다.
str
원래 문자열 인 경우substr
확인하려는 하위 문자열 인 경우
strncmp(str, substr, strlen(substr))
로 시작하면가 반환
0
됩니다 . 기능 및 C 헤더 파일에있는str
substr
strncmp
strlen
<string.h>
(원래 Yaseen Rauf here 게시 , 마크 업 추가)
대소 문자를 구분하지 않으려면 strnicmp
대신을 사용하십시오 strncmp
.
이것은 C 방법입니다 .C ++ 문자열의 경우 다음과 같은 기능을 사용할 수 있습니다.
strncmp(str.c_str(), substr.c_str(), substr.size())
memcmp()
이미 Boost를 사용하고 있다면 boost string algorithms + lexical cast boost를 사용하여 수행 할 수 있습니다 .
#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는 하나 ( Boost.Program_options )를 가지고 있으며, 이미 Boost를 사용하고 있다면 의미가 있습니다.
그렇지 않으면 "c ++ 명령 줄 파서"를 검색하면 여러 가지 옵션이 나타납니다.
내가 사용하는 코드 :
std::string prefix = "-param=";
std::string argument = argv[1];
if(argument.substr(0, prefix.size()) == prefix) {
std::string argumentValue = argument.substr(prefix.size());
}
substr
하면 불필요한 복사가 발생합니다. str.compare(start, count, substr)
에 사용되는 방법 토마스의 대답은 더 효율적입니다. razvanco13의 답변 에는을 사용하여 복사를 피하는 또 다른 방법이 있습니다 std::equal
.
Thomas uses atoi which is only for windows
Huh? atoi
그 이후로 C 표준 라이브러리 함수였습니다. 사실의 점에서, atoi
그것의 윈도우 특정 -이 있지만,의 (1) C가 아니라 C ++, 그리고 (2)도 C에서 사용되지 않는 때문에 (사용해야하지 때문에 bad-이다 strtol
또는 다른 관련 기능 중 하나. 때문에이 atoi
있다 오류 처리는 없지만 다시 C에 있습니다).
아직 아무도 STL 알고리즘 / 미스 매치 기능을 사용하지 않았습니다. 이것이 true를 반환하면 prefix는 '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;
}
}
std::equal
문자열에 사용 하면 문자열 끝을 감지하지 못하는 단점이 있으므로 접두어가 전체 문자열보다 짧은 지 수동으로 확인해야합니다. (예제 프로그램에서 올바르게 수행되었지만 위의 한 줄짜리에서는 생략되었습니다.)
@FelixDombek의 답변 은 C argv[1]
와 현 모두 "--foo"
C 스트링 이라는 점을 감안할 때 최상의 솔루션입니다.
그러나 다른 답변을 보면 텍스트가 이미로 사용할 수 있다면 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());
rfind(x, 0) == 0
실제로 표준으로 정의되어야합니다starts_with
rfind()
(대신 startswith()
)는 매우 비효율적이므로 문자열 끝까지 검색을 계속합니다.
C ++ 17을 사용하면 사용할 수 있습니다 std::basic_string_view
및 20 ++ C와 std::basic_string::starts_with
나 std::basic_string_view::starts_with
.
메모리 관리와 관련 std::string_view
하여 이점은 std::string
"문자열"(문자열 객체의 연속 된 시퀀스)에 대한 포인터 만 보유하고 크기를 알고 있다는 것입니다. 정수 값을 얻기 위해 소스 문자열을 이동 / 복사하지 않는 예 :
#include <exception>
#include <iostream>
#include <string>
#include <string_view>
int main()
{
constexpr auto argument = "--foo=42"; // Emulating command argument.
constexpr auto prefix = "--foo=";
auto inputValue = 0;
constexpr auto argumentView = std::string_view(argument);
if (argumentView.starts_with(prefix))
{
constexpr auto prefixSize = std::string_view(prefix).size();
try
{
// The underlying data of argumentView is nul-terminated, therefore we can use data().
inputValue = std::stoi(argumentView.substr(prefixSize).data());
}
catch (std::exception & e)
{
std::cerr << e.what();
}
}
std::cout << inputValue; // 42
}
std::atoi
완전히 괜찮습니다. 잘못된 입력 (이 코드에서 처리됨)에서 예외가 발생합니다. 다른 것을 염두에 두셨습니까?
atoi
대신에 실수로 이야기하고있는 것 같습니다 std::atoi
. 첫 번째는 사용하기에 안전하지 않지만 후자는 괜찮습니다. 여기 코드에서 후자를 사용하고 있습니다.
std::atoi
적절한 참고 문헌을 인용하여 실제로 예외를 던진다는 것을 증명하십시오 . 당신이 할 때까지 나는 완전히 다른 방식으로 행동 ::atoi
하고 std::atoi
행동하는 것이 매우 혼란 스러울 것이기 때문에 당신을 믿지 않습니다 .
std::atoi
대신에 사용 된 감독 이었습니다 std::stoi
. 나는 그것을 고쳤다.
text.substr(0, start.length()) == start
if (one-liner)
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;
}
if (prefix.size()<=arg.size() && std::equal(...))
.
C 구문을 사용하여 화를 낼 위험이 있으므로이 sscanf
예제는 대부분의 Boost 솔루션보다 더 우아 하다고 생각합니다 . 그리고 파이썬 인터프리터가있는 곳이라면 어디에서든 연결에 대해 걱정할 필요가 없습니다!
#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
argv[i]
이다 "--foo=9999999999999999999999999"
(대부분 또는 모든 구현이 올바로 수행 행동해야하지만), 동작은 정의되지 않는다. 나는 가정하고있다 9999999999999999999999999 > INT_MAX
.
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
C ++ 11 호환성이 필요하고 부스트를 사용할 수없는 경우 사용 예제가 포함 된 부스트 호환 드롭 인이 있습니다.
#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;
}
왜 라이브러리와 물건을 복잡하게 사용합니까? C ++ String 객체는 [] 연산자를 오버로드하므로 문자를 비교할 수 있습니다. 디렉토리에있는 모든 파일을 나열하고 보이지 않는 파일과 .. 및. 의사 파일.
while ((ep = readdir(dp)))
{
string s(ep->d_name);
if (!(s[0] == '.')) // Omit invisible files and .. or .
files.push_back(s);
}
그렇게 간단합니다 ..
11 사용할 수있는 높은 C ++로 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
}
행운을 빕니다!
C ++ 11 std::regex_search
을 사용하면 더 복잡한 표현식 일치를 제공 할 수도 있습니다. 다음 예제는 부동 소수 점수 std::stof
와 이후의 캐스트도 처리합니다 int
.
그러나 접두사가 일치하지 않으면 parseInt
아래에 표시된 메소드에서 std::invalid_argument
예외가 발생할 수 있습니다 . 주어진 응용 프로그램에 따라 쉽게 조정할 수 있습니다.
#include <iostream>
#include <regex>
int parseInt(const std::string &str, const std::string &prefix) {
std::smatch match;
std::regex_search(str, match, std::regex("^" + prefix + "([+-]?(?=\\.?\\d)\\d*(?:\\.\\d*)?(?:[Ee][+-]?\\d+)?)$"));
return std::stof(match[1]);
}
int main() {
std::cout << parseInt("foo=13.3", "foo=") << std::endl;
std::cout << parseInt("foo=-.9", "foo=") << std::endl;
std::cout << parseInt("foo=+13.3", "foo=") << std::endl;
std::cout << parseInt("foo=-0.133", "foo=") << std::endl;
std::cout << parseInt("foo=+00123456", "foo=") << std::endl;
std::cout << parseInt("foo=-06.12e+3", "foo=") << std::endl;
// throw std::invalid_argument
// std::cout << parseInt("foo=1", "bar=") << std::endl;
return 0;
}
정규식 패턴의 마법 종류는 다음 답변에 자세히 설명되어 있습니다.
편집 : 이전 답변은 정수로 변환하지 않았습니다.
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()));
이것은 완전히 테스트되지 않았습니다. 원리는 파이썬과 같습니다. Boost.StringAlgo 및 Boost.LexicalCast가 필요합니다.
문자열이 다른 문자열로 시작하는지 확인한 다음 첫 번째 문자열의 하위 문자열 ( '슬라이스')을 가져와 어휘 캐스트를 사용하여 변환하십시오.