2011-01-22 43 views
57

Có gì giống như startsWith(str_a, str_b) trong thư viện C chuẩn không?Cách kiểm tra xem chuỗi có bắt đầu bằng một chuỗi khác trong C không?

Nó sẽ đưa con trỏ đến hai chuỗi kết thúc bằng nullbyte và cho tôi biết chuỗi đầu tiên cũng xuất hiện hoàn toàn ở đầu chuỗi thứ hai hay không.

Ví dụ:

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

Tôi nghĩ ví dụ thứ 3 của bạn sẽ có kết quả thực sự. –

+0

@Burr: Có, đúng. – thejh

Trả lời

52

Rõ ràng không có chức năng C tiêu chuẩn cho việc này. Vì vậy:

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

Lưu ý rằng ở trên là tốt đẹp và rõ ràng, nhưng nếu bạn đang làm việc đó trong một vòng lặp chặt chẽ hoặc làm việc với rất chuỗi lớn, nó có thể không cung cấp hiệu suất tốt nhất, như nó quét toàn bộ chiều dài của cả hai dây lên phía trước (strlen). Các giải pháp như wj32's hoặc Christoph's có thể cung cấp hiệu suất tốt hơn (mặc dù this comment về vectơ hóa nằm ngoài ken của tôi về C). Cũng xin lưu ý Fred Foo's solution để tránh strlen trên str (anh ấy đúng, không cần thiết). Chỉ có các vấn đề cho (rất) các chuỗi lớn hoặc sử dụng lặp lại trong các vòng chặt chẽ, nhưng khi nó quan trọng, nó quan trọng.

+5

Tôi nên đề cập rằng các * thông thường * điều sẽ được cho chuỗi là tham số đầu tiên, và tiền tố để được thứ hai. Nhưng tôi giữ chúng như trên bởi vì dường như câu hỏi của bạn được đóng khung ... Thứ tự hoàn toàn tùy thuộc vào bạn, nhưng tôi thực sự nên làm theo cách khác 'vòng - hầu hết các hàm chuỗi lấy chuỗi đầy đủ như đối số đầu tiên, chuỗi con thứ hai. –

+1

Đây là một giải pháp thanh lịch, nhưng nó có một số vấn đề hiệu suất. Việc triển khai tối ưu hóa sẽ không bao giờ xem xét nhiều hơn các ký tự nhỏ (strlen (trước), strlen (str)) từ mỗi chuỗi, cũng như không bao giờ nhìn xa hơn sự không khớp đầu tiên. Nếu các chuỗi dài, nhưng sự không phù hợp sớm là phổ biến, nó sẽ rất nhẹ. Nhưng kể từ khi thực hiện này mất chiều dài đầy đủ của cả hai dây ngay lên phía trước, nó buộc hiệu suất trường hợp xấu nhất, ngay cả khi các chuỗi khác nhau trong nhân vật đầu tiên. Cho dù điều này thực sự phụ thuộc vào hoàn cảnh, nhưng đó là một vấn đề tiềm năng. –

+0

@TomKarzes: Tuyệt đối, tôi đã bị hư hỏng bởi các ngôn ngữ/môi trường mà độ dài chuỗi là giá trị đã biết chứ không phải là giá trị mà chúng tôi phải tìm ra. :-) [Giải pháp của wj32] (https://stackoverflow.com/a/4771055/157247) cung cấp hiệu suất tốt hơn nhiều. Chỉ có các vấn đề cho (rất) các chuỗi lớn hoặc các vòng lặp chặt chẽ, nhưng khi nó quan trọng, nó quan trọng. –

101

Không có chức năng tiêu chuẩn cho điều này, nhưng bạn có thể xác định

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

Chúng tôi không phải lo lắng về str là ngắn hơn pre vì theo tiêu chuẩn C (7.21.4.4/2):

Chức năng strncmp so sánh không hơn n ký tự (nhân vật mà theo một ký tự null không so) từ mảng trỏ đến bởi s1 để mảng trỏ đến bởi s2."

+4

Tại sao câu trả lời là không? Rõ ràng, câu trả lời là có, nó được gọi là 'strncmp'. – Jasper

5

Tôi không phải chuyên gia trong việc viết mã thanh lịch, nhưng ...

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

Sử dụng strstr() chức năng. Stra == strstr(stra, strb)

+1

mà có vẻ là một số cách ngược lại để làm điều đó - bạn sẽ đi qua toàn bộ căng thẳng mặc dù nó phải rõ ràng từ phân khúc ban đầu rất ngắn nếu strb là một tiền tố hay không. – StasM

22

tôi có lẽ muốn đi với strncmp(), nhưng chỉ để cho vui một thực hiện liệu:

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

    return 1; 
} 
+6

Tôi thích điều này nhất - không có lý do gì để quét một trong hai chuỗi cho một độ dài. –

+1

Tôi có lẽ sẽ đi với strlen + strncmp quá, nhưng mặc dù nó trong thực tế công việc, tất cả các tranh cãi về định nghĩa mơ hồ của nó là đưa tôi đi. Vì vậy, tôi sẽ sử dụng điều này, cảm ơn. –

+4

Điều này có thể chậm hơn 'strncmp', trừ khi trình biên dịch của bạn thực sự tốt tại vectorization, bởi vì các nhà văn glibc chắc chắn là :-) –

1

Bởi vì tôi chạy phiên bản chấp nhận và đã có một vấn đề với một str rất lâu, tôi đã phải thêm vào logic sau:

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

Tối ưu hóa (v.2 - sửa chữa.):

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

bỏ phiếu phủ định:' startsWith ("\ 2", "\ 1") 'trả về 1, 'startsWith (" \ 1 "," \ 1 ")' cũng trả về 1 – thejh

+0

Bạn nói đúng. Có một dòng sai. – Zloten

+0

Có vẻ tốt! :) – thejh

-5

Tối ưu hóa:

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

    return *s2 == 0; 
} 
+2

Bạn đã thử 'StartsWith (" "," ")'? – Neil

Các vấn đề liên quan