2011-01-22 90 views
57

标准C库中是否有类似startsWith(str_a, str_b)的东西?如何检查一个字符串是否以C中的另一个字符串开头?

它应该指向以nullbytes结尾的两个字符串,并告诉我第一个字符串是否也完全出现在第二个字符串的开头。

例子:

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

我认为你的第三个例子应该有一个真实的结果。 – 2011-01-23 06:19:50

+0

@Burr:是的,没错。 – thejh 2011-01-23 11:24:42

回答

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'sChristoph's之类的解决方案可能会提供更好的性能(尽管关于矢量化的this comment超出了我对C的评价)。还请注意Fred Foo's solution,它在str上避免了strlen(他是对的,这是不必要的)。只对(非常)大的琴弦或在紧密环路中重复使用很重要,但重要时,它很重要。

+5

我应该提到*通常*的事情是将字符串作为第一个参数,并将其作为前缀。但我像上面一样保留它们,因为这似乎是你的问题是如何构建的......顺序完全取决于你,但我真的应该以另一种方式完成它 - 大多数字符串函数都采用完整字符串作为第一个参数,子字符串作为第二个参数。 – 2011-01-22 22:31:03

+1

这是一个优雅的解决方案,但确实有一些性能问题。一个优化的实现永远不会从每个字符串中查看超过min(strlen(pre),strlen(str))字符,也不会超越第一个不匹配。如果琴弦很长,但早期的不匹配很常见,它会非常轻便。但是由于这个实现将两个字符串的全部长度都放在前面,所以即使字符串在第一个字符中不同,它也会强制最差情况下的性能。这是否真的取决于具体情况,但这是一个潜在的问题。 – 2018-01-06 11:33:02

+0

@TomKarzes:当然,我被字符串长度是一个已知值的语言/环境所迷惑,而不是我们必须弄清楚的。 :-) [wj32的解决方案](https://stackoverflow.com/a/4771055/157247)提供更好的性能。只对(非常)大字符串或紧密循环很重要,但重要时,它很重要。 – 2018-01-06 11:38:00

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字符(即跟随一个空字符的字符不进行比较)从阵列比较指向s1到阵列由s2指向。”

+4

为什么答案不是?显然,答案是肯定的,它被称为`strncmp`。 – Jasper 2017-02-13 00:39:39

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是一个前缀,那么即使它应该从非常短的初始段中清楚,您仍然会穿过整个stra。 – StasM 2011-01-22 23:02:04

22

我可能会用strncmp()去,但只是为了好玩原始的实现:

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

    return 1; 
} 
1

因为我跑了接受的版本并且有一个很长的STR一个问题,我不得不在增加以下逻辑:

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

优化:

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

    return *s2 == 0; 
} 
相关问题