2011-01-22 16 views
57

Standart C kitaplığında startsWith(str_a, str_b) gibi bir şey var mı?Bir dizgenin C içinde başka bir dizeyle başlayıp başlamadığını nasıl kontrol edilir?

Nullbayt ile biten iki dizeye işaretçiler almalı ve ilkinin de ikincisinin başlangıcında tamamen görünüp görünmeyeceğini söyle.

Örnekler:

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

Üçüncü örneğinizin doğru bir sonucu olması gerektiğini düşünüyorum. –

+0

@Burr: Evet, doğru. – thejh

cevap

52

Görünüşe bunun için standart bir C fonksiyonu var. Yani: olarak, yukarıda güzel ve net olduğunu, ancak sıkı bir döngü içinde bunu yapıyor ya çok büyük dizeleri ile çalışıyorsanız, en iyi performans sunan olmayabilir

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

Not

her iki dizginin tam uzunluğunu tarar ( strlen). wj32's veya Christoph's gibi çözümler daha iyi bir performans sunabilir (her ne kadar this comment, vektörizasyon ile ilgili olarak C'nin kenarımın ötesindedir). Ayrıca, str numaralı telefondan strlen'u önleyen Fred Foo's solution numaralı notu (doğru, gereksiz). Sadece (çok) geniş dizgiler veya sıkı döngülerde tekrarlanan kullanım için önemlidir, ancak önemli olduğunda önemlidir.

+5

Dizinin ilk parametresi olması için * olağan * olayı ve ikincisinin öneki olacağından bahsetmeliyim. Ama ben onları yukarıdaki gibi tuttum çünkü senin sorunun nasıl çerçevelenmiş gibi görünüyor ... Emir tamamen size kalmış, ama gerçekten bunu diğer yoldan yapmış olmalıyım - çoğu dize işlevleri tam dizeyi İlk argüman, ikinci olarak substring. –

+1

Bu zarif bir çözümdür, ancak bazı performans sorunları vardır. Optimize edilmiş bir uygulama, her bir dizeden en fazla (strlen (pre), strlen (str)) karakterden daha fazlasını görmez ve ilk uyumsuzluğun ötesine bakmaz. Dizeler uzunsa, ancak erken uyumsuzluklar yaygındı, çok hafif olurdu. Ancak bu uygulama, her iki dizenin tam uzunluğunu tam önüne aldığından, dizeler ilk karakterde farklı olsa bile, en kötü performansı zorlar. Bunun önemli olup olmadığı gerçekten de şartlara bağlı, ama bu potansiyel bir problem. –

+0

@TomKarzes: Kesinlikle, dize uzunluğunun bilinen bir değer olduğunu anlamaya çalışmak yerine, dil/ortam tarafından bozuldum. :-) [wj32'nin çözümü] (https://stackoverflow.com/a/4771055/157247) çok daha iyi bir performans sunuyor. Sadece (çok) büyük dizeler veya sıkı döngüler için önemlidir, ancak önemli olduğunda, önemli. –

101

Bunun için bir standart fonksiyon, ama Tanımlayabileceğiniz

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

Biz endişelenmenize gerek yok yaklaşık str C standardına göre çünkü daha kısa pre olmak (7.21.4.4/2):

strncmp işlevi diziden (karşılaştırıldığında edilmez bir boş karakter izleyin karakter) fazla olmamak n karakterden karşılaştırır diziye s1s2 tarafından işaret tarafından işaret etti."

+4

Neden cevap yok? Açıkçası, cevap evet, 'strncmp' denir. – Jasper

5

ben ...

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

Kullanım strstr() fonksiyon zarif kod yazarken hiç uzman değilim, ama. Stra == strstr(stra, strb)

+1

bir şekilde geriye doğru gidiyor gibi görünüyor - strb bir önek veya değilse, çok kısa başlangıç ​​segmentinden açık olsa bile tüm stra boyunca ilerleyeceksiniz. – StasM

22

Muhtemelen sadece eğlence için bir ham uygulama strncmp() ile gitmek ederdim ama : Kabul versiyonunu koştu ve çok uzun bir str ile ilgili bir sorun vardı çünkü

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

    return 1; 
} 
+6

Bunu en çok beğendim - uzunluğa göre dizgileri taramak için bir sebep yok. –

+1

Muhtemelen strlen + strncmp ile de giderdim, ama aslında işe yaramamış olsa da, belirsiz tanımıyla ilgili tüm tartışmalar beni etkisiz hale getiriyor. Böylece bunu kullanacağım, teşekkürler. –

+4

Denkleminiz vektörleştirmede gerçekten iyi olmadıkça, strncmp'den daha yavaş olması muhtemeldir, çünkü glibc yazarları :-) –

1

, içeri eklemek zorunda aşağıdaki mantık:

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

Optimize (v.2'dir - düzeltildi.):

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

oylama negatiftir: 'startWith (" \ 2 "," \ 1 ")' return 1, startWith ("\ 1", "\ 1") 'da 1 – thejh

+0

değerini döndürür. Haklısınız. Bir yanlış çizgi vardı. – Zloten

+0

Şimdi iyi görünüyor! :) – thejh

-5

En İyileştirilmiş:

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

    return *s2 == 0; 
} 
+2

'StartsWith (" "," ")' yi denediniz mi? – Neil

İlgili konular