2011-01-22 3 views
57

표준 C 라이브러리에 startsWith(str_a, str_b)과 같은 것이 있습니까?C에서 문자열이 다른 문자열로 시작하는지 확인하는 방법은 무엇입니까?

nullbytes로 끝나는 두 개의 문자열에 대한 포인터를 취해야하며 첫 번째 문자열이 두 번째 문자열의 시작 부분에 완전히 나타나는지 여부를 알려줘야합니다.

예 :

"abc", "abcdef" -> true 
"abcdef", "abc" -> false 
"abd", "abdcef" -> true 
"abc", "abc" -> true 
+2

제 3의 예는 진정한 결과를 가져야한다고 생각합니다. –

+0

@Burr : 예, 맞습니다. – thejh

답변

52

는 분명히 이것에 대한 표준 C 함수가 없습니다. 그래서 :로, 위의 좋은 분명하지만, 당신이 꽉 루프에서 그 일을 또는 매우 큰 문자열로 작업하는 경우, 그것은 최고의 성능을 제공하지 않을 수도 있음을

bool startsWith(const char *pre, const char *str) 
{ 
    size_t lenpre = strlen(pre), 
      lenstr = strlen(str); 
    return lenstr < lenpre ? false : strncmp(pre, str, lenpre) == 0; 
} 

두 줄 앞의 전체 길이를 스캔합니다 ( strlen). wj32's 또는 Christoph's과 같은 솔루션을 사용하면 더 나은 성능을 제공 할 수 있습니다 (벡터화에 대해서는 this comment이 내 C보다 낫습니다). 또한 Fred Foo's solution을 참고하면 strlenstr에 있습니다 (맞아요, 불필요합니다). 엄격한 루프에서 (매우) 큰 문자열이나 반복적 인 사용에 대해서만 중요하지만 중요한 경우 중요합니다.

+5

필자는 문자열이 첫 번째 매개 변수가 될 것이고 두 번째는 접두사가 될 것이라고 평소 * 언급해야합니다. 하지만 당신의 질문이 틀에 박힌 것처럼 보였기 때문에 위와 같이 유지했습니다 ... 명령은 전적으로 당신에게 달려 있습니다. 그러나 나는 다른 방법으로 돌았어야합니다 - 대부분의 문자열 함수는 첫 번째 인수는 하위 문자열을 두 번째 인수로 사용합니다. –

+1

이것은 우아한 솔루션이지만 성능 문제가 있습니다. 최적화 된 구현은 각 문자열에서 min (strlen (pre), strlen (str)) 문자 이상을 보지 않으며 첫 번째 불일치를 넘어서 보지도 않습니다. 문자열이 길지만 초기 불일치가 일반적인 경우 매우 가볍습니다. 그러나이 구현은 두 문자열의 전체 길이를 바로 앞에서 가져 오므로 문자열이 첫 문자에서 다른 경우에도 최악의 경우 성능을 유지합니다. 이 문제가 실제로 상황에 달려 있는지 여부는 문제가 될 수 있습니다. –

+0

@TomKarzes : 당연히 문자열 길이가 알려진 값 이라기보다는 언어/환경에 의해 망가졌습니다. :-) [wj32의 해결책] (https://stackoverflow.com/a/4771055/157247)은 훨씬 더 나은 성능을 제공합니다. (매우) 큰 끈이나 좁은 고리에만 중요하지만, 중요 할 때는 중요합니다. –

101

가이에 대한 표준 기능은 없지만 사용자가 정의 할 수

bool prefix(const char *pre, const char *str) 
{ 
    return strncmp(pre, str, strlen(pre)) == 0; 
} 

우리는 걱정할 필요가 없습니다에 대한 str C 표준에 따라 있기 때문에보다 짧은 pre 인 (7.21.4.4/2) :

strncmp 배열에서 (비교되지 널 문자에 따라 문자)하지 더 n 이상의 문자를 비교 배열에 s1s2가 가리키는 가리키는. "

+4

대답이 '아니오'인 이유는 무엇입니까? 분명히 대답은 '예. strncmp'입니다. – Jasper

5

나는 ...

int prefix(const char *pre, const char *str) 
{ 
    char cp; 
    char cs; 

    if (!*pre) 
     return 1; 

    while ((cp = *pre++) && (cs = *str++)) 
    { 
     if (cp != cs) 
      return 0; 
    } 

    if (!cs) 
     return 0; 

    return 1; 
} 
4

사용 strstr() 기능 우아한 코드를 작성에 전문가는 아니지만. Stra == strstr(stra, strb)

+1

다소 뒤틀리는 것처럼 보이는 것처럼 보입니다. strb가 접두어인지 아닌지는 아주 짧은 초기 세그먼트에서 분명해야하지만 전체 스트레이트를 통과하게됩니다. – StasM

22

아마 그냥 재미를위한 원시 구현 strncmp()과 함께 할 것입니다,하지만 것 : 나는 허용 버전을 실행하고 매우 긴 STR에 문제가 있었기 때문에

_Bool starts_with(const char *restrict string, const char *restrict prefix) 
{ 
    while(*prefix) 
    { 
     if(*prefix++ != *string++) 
      return 0; 
    } 

    return 1; 
} 
+6

나는이 최고가 마음에 든다. 어느 길이의 문자열을 스캔 할 이유가 없다. –

+1

나는 아마도 strlen + strncmp와 함께 갈 것이다. 그러나 실제로 작동하지만, 모호한 정의를 둘러싼 모든 논쟁은 나를 없애고있다. 그래서 이것을 사용하겠습니다. 고마워요. –

+4

glibc 작성자가 확실하기 때문에 컴파일러가 벡터화를 잘하지 않는 한'strncmp'보다 느릴 수 있습니다 : –

1

, 나는에 추가했다 다음과 같은 논리 :

bool longEnough(const char *str, int min_length) { 
    int length = 0; 
    while (str[length] && length < min_length) 
     length++; 
    if (length == min_length) 
     return true; 
    return false; 
} 

bool startsWith(const char *pre, const char *str) { 
    size_t lenpre = strlen(pre); 
    return longEnough(str, lenpre) ? strncmp(str, pre, lenpre) == 0 : false; 
} 
1

최적화 (2 절 - 수정.) :

uint32 startsWith(const void* prefix_, const void* str_) { 
    uint8 _cp, _cs; 
    const uint8* _pr = (uint8*) prefix_; 
    const uint8* _str = (uint8*) str_; 
    while ((_cs = *_str++) & (_cp = *_pr++)) { 
     if (_cp != _cs) return 0; 
    } 
    return !_cp; 
} 
+1

투표 부정 :'startsWith ("\ 2", "\ 1")'은 1을 반환하고, 'startsWith ("\ 1", "\ 1")'또한 1을 반환합니다. – thejh

+0

맞습니다. 잘못된 라인이 하나 있습니다. – Zloten

+0

좋아 보인다! :) – thejh

-5

최적화 됨 :

boolean StartsWith(char *s1, char *s2) 
{ 
    while (*s1++ == *s2++) 
    { 
    } 

    return *s2 == 0; 
} 
+2

'StartsWith ("", "")'시도 했습니까? – Neil

관련 문제