C ++에서 문자열이 다른 문자열로 끝나는 지 확인


270

C ++에서 문자열이 다른 문자열로 끝나는 지 어떻게 알 수 있습니까?

답변:


211

다음을 사용하여 마지막 n 문자를 간단히 비교하십시오 std::string::compare.

#include <iostream>

bool hasEnding (std::string const &fullString, std::string const &ending) {
    if (fullString.length() >= ending.length()) {
        return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending));
    } else {
        return false;
    }
}

int main () {
    std::string test1 = "binary";
    std::string test2 = "unary";
    std::string test3 = "tertiary";
    std::string test4 = "ry";
    std::string ending = "nary";

    std::cout << hasEnding (test1, ending) << std::endl;
    std::cout << hasEnding (test2, ending) << std::endl;
    std::cout << hasEnding (test3, ending) << std::endl;
    std::cout << hasEnding (test4, ending) << std::endl;

    return 0;
}

네, 의심 할 여지없이 최선의 방법입니다.
Noldorin

3
나는 항상 부분 문자열의 인덱스를 계산하는 것을 싫어합니다. 매우 까다 롭습니다 ... 두 문자열의 끝에서 뒤로 반복하여 불일치를 찾으려고합니다.
xtofl

17
@Noldorin 동의하지 않습니다. 이것은 가장 쉬운 방법입니다. 라이브러리를 사용하는 것이 가장 좋습니다. C ++ 표준 라이브러리가 유용한 일을 거의하지 않는 것은 부끄러운 일입니다.
masterxilo

1
@masterxilo이 문제를 해결하기 위해 어떤 라이브러리를 제안하고 그 라이브러리가 (기본적으로) 한 줄 함수보다 더 나은 선택입니까?
Brandin

33
@Brandin 기본 기능이기 때문입니다. C ++은 다른 현대 컴퓨터 언어에서 기본적으로 제공되는 것과 동일한 기능을 반복해서 다시 프로그래밍하도록합니다. 사람들 이이 질문을 해결하기 위해 stackoverflow로 가야한다는 사실은 pb가 있음을 보여줍니다.
Conchylicultor

175

이 기능을 사용하십시오 :

inline bool ends_with(std::string const & value, std::string const & ending)
{
    if (ending.size() > value.size()) return false;
    return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
}

3
MSVC10은이 솔루션을 좋아하지 않습니다 std::equal(suffix.rbegin(), suffix.rend(), str.rbegin(). 디버그 모드에서는 다음이 발생합니다._DEBUG_ERROR("string iterator not decrementable");
remi.chateauneu

154

사용하십시오 boost::algorithm::ends_with(예 : http://www.boost.org/doc/libs/1_34_0/doc/html/boost/algorithm/ends_with.html 참조 ) :

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

// works with const char* 
assert(boost::algorithm::ends_with("mystring", "ing"));

// also works with std::string
std::string haystack("mystring");
std::string needle("ing");
assert(boost::algorithm::ends_with(haystack, needle));

std::string haystack2("ng");
assert(! boost::algorithm::ends_with(haystack2, needle));

83

c ++ 20 std :: string 부터 시작 하면 결국 starts_withends_with를 제공합니다 . 먼 미래에서 이것을 읽지 않으면 c ++의 c ++ 30 문자열이 마침내 사용 가능해질 가능성이있는 것처럼 보입니다. 먼저 다음과 같이 startsWith / endsWith를 사용할 수 있습니다.

#include <string>

static bool endsWith(const std::string& str, const std::string& suffix)
{
    return str.size() >= suffix.size() && 0 == str.compare(str.size()-suffix.size(), suffix.size(), suffix);
}

static bool startsWith(const std::string& str, const std::string& prefix)
{
    return str.size() >= prefix.size() && 0 == str.compare(0, prefix.size(), prefix);
}

추가 도우미 오버로드 :

static bool endsWith(const std::string& str, const char* suffix, unsigned suffixLen)
{
    return str.size() >= suffixLen && 0 == str.compare(str.size()-suffixLen, suffixLen, suffix, suffixLen);
}

static bool endsWith(const std::string& str, const char* suffix)
{
    return endsWith(str, suffix, std::string::traits_type::length(suffix));
}

static bool startsWith(const std::string& str, const char* prefix, unsigned prefixLen)
{
    return str.size() >= prefixLen && 0 == str.compare(0, prefixLen, prefix, prefixLen);
}

static bool startsWith(const std::string& str, const char* prefix)
{
    return startsWith(str, prefix, std::string::traits_type::length(prefix));
}

IMO, c ++ 문자열은 분명히 기능 장애이며 실제 코드에서 사용되도록 만들어지지 않았습니다. 그러나 이것이 더 좋아질 것이라는 희망이 있습니다.


2
str.compare는 부울을 반환하지 않기 때문에 독자에게 혼란을 줄 수 있으므로 not ( "!") 연산자를 사용하여 "== 0"을 테스트하는 것은 현명하지 않습니다. 명확성을 위해 "... && str.compare (...) == 0"을 사용하십시오.
Thomas Tempelmann

@Pavel "startsWith"메소드에서 std :: string :: find를 사용하지 않는 이유가 있습니까?
Maxime Oudot 2016 년

4
@MaximeOudot 오프 코스가 있습니다! 무언가로 시작하는지 알아야 할 경우 왜 전체 문자열을 검색하고 싶습니까? 다시 말해, 100MB 길이의 문자열을 검색하여 마지막 부분을 찾은 다음 문자열의 시작 부분이 아니기 때문에 결과를 무시할 수 있습니다.
Pavel P

1
c ++ 30 예측을위한 "1"플러스.
무고한 방관자

40

나는 C ++에 대한 질문을 알고 있지만 누군가가 이것을하기 위해 좋은 ol'C 형 C 함수가 필요하다면 :


/*  returns 1 iff str ends with suffix  */
int str_ends_with(const char * str, const char * suffix) {

  if( str == NULL || suffix == NULL )
    return 0;

  size_t str_len = strlen(str);
  size_t suffix_len = strlen(suffix);

  if(suffix_len > str_len)
    return 0;

  return 0 == strncmp( str + str_len - suffix_len, suffix, suffix_len );
}


25

std::mismatch방법은 두 문자열의 끝에서 거꾸로 반복 할 때이 목적을 달성 할 수 있습니다.

const string sNoFruit = "ThisOneEndsOnNothingMuchFruitLike";
const string sOrange = "ThisOneEndsOnOrange";

const string sPattern = "Orange";

assert( mismatch( sPattern.rbegin(), sPattern.rend(), sNoFruit.rbegin() )
          .first != sPattern.rend() );

assert( mismatch( sPattern.rbegin(), sPattern.rend(), sOrange.rbegin() )
          .first == sPattern.rend() );

3
+1. 전에는 std :: mismatch ()를 본 적이 없었습니다. 내가 본 적이없는 알고리즘 헤더 파일에 무엇이 있는지 궁금합니다.
j_random_hacker

3
나는 그 자체로 SO 질문의 가치가 있다고 생각합니다 : 사용 가능한 STL 기능을 탐색 한 적이 있습니까?
xtofl

2
요구 사항은 std::equal다음 과 같습니다. 접미사가 예상 문자열보다 길지 않은지 미리 확인해야합니다. 확인을 무시하면 정의되지 않은 동작이 발생합니다.
Rob Kennedy

18

내 의견으로는 C ++ 솔루션은 다음과 같습니다.

bool endsWith(const string& s, const string& suffix)
{
    return s.rfind(suffix) == std::abs(s.size()-suffix.size());
}

10
문자열 s의 끝을 테스트하는 대신 전체 문자열을 검색하기 때문에 속도가 느립니다 !
Alexis Wilke

2
@ nodakai, 1Mb 문자열이 발생하면 나노 초 이상이 될 것입니다.
Alexis Wilke

나는 그렇게 생각하지 않습니다 ... 그것은 어쨌든 strlen을해야하고, 끝에서 찾고 시작합니다.
LtWorf

2
@LtWorf std::string::size()는 상수 시간 작업입니다. 필요하지 않습니다 strlen.
토마스

2
suffix.size () == s.size () + 1 인 경우 실패했을 때 어떻게 솔루션으로 간주 될 수 있습니까 ? 모든 경우에 제대로 작동하지 않으면 복잡성은 무의미합니다.
c0ntrol

10

하자 a문자열과 수 b당신이 보는 문자열입니다. 사용 a.substr의 마지막 n 문자를 얻을 수 a와 b에 비교는 (여기서 n의 길이 b)

또는 사용 std::equal(포함 <algorithm>)

전의:

bool EndsWith(const string& a, const string& b) {
    if (b.size() > a.size()) return false;
    return std::equal(a.begin() + a.size() - b.size(), a.end(), b.begin());
}

\ r 또는 \ n 또는 둘 다로 문자열 뒤에 끝나면 어떻게 true를 반환 할 수 있습니까 ??? 감사!
sofr

@Dario : std :: equal ()을 사용하는 솔루션은 훌륭하지만 substr ()을 사용하는 솔루션은별로 좋지 않습니다 .COW 문자열을 사용하지 않는 한 (그리고 소수의 사람들은 믿지 않습니다) substr ()은 두 번째 사본을 만듭니다. 문자열의 일부로 동적 메모리 할당이 포함됩니다. 이것은 실패 할 수 있으며, 어떤 경우에도 다른 솔루션보다 더 많은 메모리가 사용됨을 의미합니다 (그리고 다른 솔루션보다 거의 느립니다).
j_random_hacker

4

대소 문자를 구분하지 않는 버전으로 Joseph의 솔루션 을 확장하겠습니다 ( 온라인 데모 )

static bool EndsWithCaseInsensitive(const std::string& value, const std::string& ending) {
    if (ending.size() > value.size()) {
        return false;
    }
    return std::equal(ending.rbegin(), ending.rend(), value.rbegin(),
        [](const char a, const char b) {
            return tolower(a) == tolower(b);
        }
    );
}

3

위와 동일하게 여기 내 해결책이 있습니다.

 template<typename TString>
  inline bool starts_with(const TString& str, const TString& start) {
    if (start.size() > str.size()) return false;
    return str.compare(0, start.size(), start) == 0;
  }
  template<typename TString>
  inline bool ends_with(const TString& str, const TString& end) {
    if (end.size() > str.size()) return false;
    return std::equal(end.rbegin(), end.rend(), str.rbegin());
  }

1
starts_with'string :: compare'를 사용합니까? 왜 안돼 std::equal(start.begin(), start.end(), str.begin())?
Dmytro Ovdiienko

starts_with가 내가 필요한 첫 번째이기 때문입니다. ends_with가 나중에 추가되었습니다.
dodjango

3

또 다른 옵션은 정규식을 사용하는 것입니다. 다음 코드는 대소 문자를 구분하지 않고 검색을 수행합니다.

bool endsWithIgnoreCase(const std::string& str, const std::string& suffix) {
  return std::regex_search(str,
     std::regex(std::string(suffix) + "$", std::regex_constants::icase));
}

아마도 그렇게 효율적이지 않지만 구현하기 쉽습니다.


C ++ 11 이상인 사람에게는 매우 편리합니다.
Clare Macrae 2016 년

C ++에서 정규 표현식은 엄청나게 느릴 수 있습니다!
mxmlnkn

이것에 대한 정규식은 ... 나는 이것을 downvote해야합니다. 나는하지 않을 것이다.
MK.

2

string :: rfind를 사용할 수 있습니다

주석을 기반으로 한 전체 예 :

bool EndsWith(string &str, string& key)
{
size_t keylen = key.length();
size_t strlen = str.length();

if(keylen =< strlen)
    return string::npos != str.rfind(key,strlen - keylen, keylen);
else return false;
}

3
-1. 예, 사용할 수는 있지만 문자열이 제공된 엔딩으로 끝나지 않는 경우 불필요하게 느려집니다. 스캐닝은 문자열의 시작 부분까지 계속 계속됩니다. 또한 문자열의 다른 곳이 아니라 문자열의 끝에서 끝이 일치하는지 확인하기 위해 후속 테스트가 필요하다는 언급은 없습니다 .
j_random_hacker

방금 필요한 함수의 링크를 넣고 문서에서 쉽게 수행 할 수 있다고 생각합니다. str.rfind (key, str.length ()-key.length (), key.length ());
Ahmed 님이

좋습니다. 효율적이지만,이 경우 string :: find ()도 잘 작동합니다. 또한 key.length ()> str.length () 인 경우를 언급해야합니다.이 경우 주석에 제안한 코드가 충돌합니다. 이 정보로 답변을 업데이트하면 -1이 삭제됩니다.
j_random_hacker

2

아래를 사용하여 str접미사 가 있는지 확인하십시오 .

/*
Check string is end with extension/suffix
*/
int strEndWith(char* str, const char* suffix)
{
  size_t strLen = strlen(str);
  size_t suffixLen = strlen(suffix);
  if (suffixLen <= strLen) {
    return strncmp(str + strLen - suffixLen, suffix, suffixLen) == 0;
  }
  return 0;
}

2

<algorithms>역 반복 에서 std :: equal 알고리즘을 사용하십시오 .

std::string LogExt = ".log";
if (std::equal(LogExt.rbegin(), LogExt.rend(), filename.rbegin())) {
   
}

2
이 코드는 질문에 대한 해결책을 제공 할 수 있지만 왜 / 어떻게 작동하는지에 대한 컨텍스트를 추가하는 것이 좋습니다. 이것은 미래의 사용자가 자신의 코드를 배우고 적용 할 수 있도록 도와줍니다. 또한 코드를 설명 할 때 사용자의 의견을 공감 형태로 긍정적 인 피드백을받을 가능성이 있습니다.
borchvm

@borchvm, 일부 explaination를 추가 그것을 이해하는 데 도움이 희망
세르게이

1

Grzegorz Bazior 응답에 대하여. 이 구현을 사용했지만 원래는 버그가 있습니다 ( ".."을 ".so"와 비교하면 true를 반환 함). 수정 된 기능을 제안합니다.

bool endsWith(const string& s, const string& suffix)
{
    return s.size() >= suffix.size() && s.rfind(suffix) == (s.size()-suffix.size());
}

1

라이브러리 함수를 사용하지 않는 원시 솔루션을 게시하는 것이 합리적이라고 생각했습니다 ...

// Checks whether `str' ends with `suffix'
bool endsWith(const std::string& str, const std::string& suffix) {
    if (&suffix == &str) return true; // str and suffix are the same string
    if (suffix.length() > str.length()) return false;
    size_t delta = str.length() - suffix.length();
    for (size_t i = 0; i < suffix.length(); ++i) {
        if (suffix[i] != str[delta + i]) return false;
    }
    return true;
}

간단하게 추가하면 std::tolower이 대소 문자를 구분하지 않아도됩니다

// Checks whether `str' ends with `suffix' ignoring case
bool endsWithIgnoreCase(const std::string& str, const std::string& suffix) {
    if (&suffix == &str) return true; // str and suffix are the same string
    if (suffix.length() > str.length()) return false;
    size_t delta = str.length() - suffix.length();
    for (size_t i = 0; i < suffix.length(); ++i) {
        if (std::tolower(suffix[i]) != std::tolower(str[delta + i])) return false;
    }
    return true;
}

이것을 추가해 주셔서 감사합니다. 가벼운 솔루션은 항상 훌륭합니다
ekkis

1

비슷한 "startWith"문제에 대한이 훌륭한 답변을 찾았습니다.

C ++ std :: string이 특정 문자열로 시작하고 하위 문자열을 int로 변환하는지 어떻게 확인합니까?

문자열의 마지막 위치에서만 검색하도록 솔루션을 채택 할 수 있습니다.

bool endsWith(const std::string& stack, const std::string& needle) {
    return stack.find(needle, stack.size() - needle.size()) != std::string::npos;
}

이렇게하면 짧고 빠르며 표준 c ++을 사용하고 읽을 수 있습니다.


0

당신이 나와 같고 C ++ 순수주의에 빠져 있지 않다면 여기 오래된 스쿨 하이브리드가 있습니다. 대부분의 memcmp구현은 가능한 경우 기계어를 비교 하기 때문에 문자열이 소수 이상의 문자 인 경우 이점이 있습니다.

문자 세트를 제어해야합니다. 예를 들어,이 접근 방식이 utf-8 또는 wchar 유형과 함께 사용되는 경우 문자 매핑을 지원하지 않기 때문에 (예 : 둘 이상의 문자가 논리적으로 동일한 경우) 몇 가지 단점이 있습니다 .

bool starts_with(std::string const & value, std::string const & prefix)
{
    size_t valueSize = value.size();
    size_t prefixSize = prefix.size();

    if (prefixSize > valueSize)
    {
        return false;
    }

    return memcmp(value.data(), prefix.data(), prefixSize) == 0;
}


bool ends_with(std::string const & value, std::string const & suffix)
{
    size_t valueSize = value.size();
    size_t suffixSize = suffix.size();

    if (suffixSize > valueSize)
    {
        return false;
    }

    const char * valuePtr = value.data() + valueSize - suffixSize;

    return memcmp(valuePtr, suffix.data(), suffixSize) == 0;
}

0

내 두 센트 :

bool endsWith(std::string str, std::string suffix)
{
   return str.find(suffix, str.size() - suffix.size()) != string::npos;
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.