如何检查一个字符串是否以C中的另一个字符串开头?
标准C库中是否有类似startsWith(str_a, str_b)
的东西?如何检查一个字符串是否以C中的另一个字符串开头?
它应该指向以nullbytes结尾的两个字符串,并告诉我第一个字符串是否也完全出现在第二个字符串的开头。
例子:
"abc", "abcdef" -> true
"abcdef", "abc" -> false
"abd", "abdcef" -> true
"abc", "abc" -> true
显然有对此不存在标准的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,它在str
上避免了strlen
(他是对的,这是不必要的)。只对(非常)大的琴弦或在紧密环路中重复使用很重要,但重要时,它很重要。
我应该提到*通常*的事情是将字符串作为第一个参数,并将其作为前缀。但我像上面一样保留它们,因为这似乎是你的问题是如何构建的......顺序完全取决于你,但我真的应该以另一种方式完成它 - 大多数字符串函数都采用完整字符串作为第一个参数,子字符串作为第二个参数。 – 2011-01-22 22:31:03
这是一个优雅的解决方案,但确实有一些性能问题。一个优化的实现永远不会从每个字符串中查看超过min(strlen(pre),strlen(str))字符,也不会超越第一个不匹配。如果琴弦很长,但早期的不匹配很常见,它会非常轻便。但是由于这个实现将两个字符串的全部长度都放在前面,所以即使字符串在第一个字符中不同,它也会强制最差情况下的性能。这是否真的取决于具体情况,但这是一个潜在的问题。 – 2018-01-06 11:33:02
@TomKarzes:当然,我被字符串长度是一个已知值的语言/环境所迷惑,而不是我们必须弄清楚的。 :-) [wj32的解决方案](https://stackoverflow.com/a/4771055/157247)提供更好的性能。只对(非常)大字符串或紧密循环很重要,但重要时,它很重要。 – 2018-01-06 11:38:00
有这个没有标准的功能,但你可以定义
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
指向。”
为什么答案不是?显然,答案是肯定的,它被称为`strncmp`。 – Jasper 2017-02-13 00:39:39
我在写优雅的代码专家,但...
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;
}
使用strstr()
功能。 Stra == strstr(stra, strb)
这似乎有点倒退 - 如果strb是一个前缀,那么即使它应该从非常短的初始段中清楚,您仍然会穿过整个stra。 – StasM 2011-01-22 23:02:04
我可能会用strncmp()
去,但只是为了好玩原始的实现:
_Bool starts_with(const char *restrict string, const char *restrict prefix)
{
while(*prefix)
{
if(*prefix++ != *string++)
return 0;
}
return 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;
}
优化(第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;
}
优化:
boolean StartsWith(char *s1, char *s2)
{
while (*s1++ == *s2++)
{
}
return *s2 == 0;
}
我认为你的第三个例子应该有一个真实的结果。 – 2011-01-23 06:19:50
@Burr:是的,没错。 – thejh 2011-01-23 11:24:42