如何在C语言中比较字符串的结尾?

57

我想确保我的字符串以“.foo”结尾。我正在使用C语言,这是我不太熟悉的语言。我找到了下面的最佳方法来实现它。有没有C语言专家能够验证我是否优雅而明智地完成了这个任务?

int EndsWithFoo(char *str)
{
    if(strlen(str) >= strlen(".foo"))
    {
        if(!strcmp(str + strlen(str) - strlen(".foo"), ".foo"))
        {
            return 1;
        }
    }
    return 0;
}

1
25个答案,只有4或5个没有问题。 - chqrlie
25个回答

-1

你也可以这样泛化:

int endsWith(const char* text, const char* extn)
{
    int result = 1;
    int len = strlen(text);
    int exprLen = strlen(extn);
    int index = len-exprLen;
    int count = 0;

    if(len > exprLen)
    {
        for( ; count  < exprLen; ++count)
        {
            if(text[index + count] != extn[count])
            {
                result = 0;
                break;
            }

        }
    }
    else
    {
        result = 0;
    }
    return result;
}

如果 textextn 的内容完全相同,您的解决方案将返回 0,这似乎是不正确的。此外,请使用 size_t 作为索引变量。 - chqrlie

-1

使用一个strlen(needle),strstr()和测试'\ 0'的通用解决方案:

#include <stdio.h>
#include <string.h>
#include <stdbool.h>

bool endsWith(const char* haystack, const char* needle)
{
    bool rv = false;
    if (haystack && needle)
    {
        size_t needle_size = strlen(needle);
        if (needle_size == 0) return false;
        const char* act = haystack;
        while (NULL != (act = strstr(act, needle)))
        {   
            if (*(act + needle_size) == '\0')
            {   
                rv = true;
                break;
            }
            act += 1;
        }
    }

    return rv;
}

int main (int argc, char * argv[])
{
    char *a = "file1.gz";
    char *b = "1.gz";
    char *c = NULL;
    char *d = "1.gzabc";
    char *e = "1.gzabc1.gz";
    char *f = "";
    char *g = "rbrbr";
    char *h = "rbr";

    printf("endsWith:\n");
    printf("'%s' '%s' = %d\n",a,b,endsWith(a,b));
    printf("'%s' NULL = %d\n",a,endsWith(a,c));
    printf("'%s' '%s' = %d\n",d,b,endsWith(d,b));
    printf("'%s' '%s' = %d\n",e,b,endsWith(e,b));
    printf("'%s' '%s' = %d\n",e,f,endsWith(e,f));
    printf("'%s' '%s' = %d\n",g,h,endsWith(g,h));

    return 0;
}

这个解决方案在 needle = "" 的情况下会出现无限循环。此外,它无法匹配字符串 "rbrbr" 的后缀 "rbr"。为了解决这个问题,应该将 act += needle_size; 改为 act += 1;,这样在极端情况下效率会更差。 - chqrlie
@chqrlie:我已经添加了这些更改,感谢您的评论。 - lumpidu
needle 为空字符串时,应该返回 true - chqrlie
从逻辑上讲这可能是正确的,因为\0即空字符串是每个C字符串的结尾,但你能否给我一个直觉,说明传递空字符串是有意而为之而不是错误的后果? - lumpidu

-1
在 POSIX 系统中,您可以使用 glob 模式匹配字符串的结尾。
#include <fnmatch.h>

if (fnmatch("*.foo", my_string, 0))
  /* match */

-2
我会这样做:
/**
  * Return 0 if the string haystack ends with the string needle
  * 
  * @param haystack the string to be analyzed
  * @param needle the suffix string
  * @return 0 if the string haystack ends with the string needle, 1 if not
*/
int strbcmp(const char *haystack, const char *needle) {
    int length;
    if (haystack && needle && strlen(haystack) >= (length = strlen(needle)) && strlen(strstr(haystack, needle)) == length) return 0;
   return 1;
}

测试程序如下:
#include <stdio.h>
#include <string.h>

int strbcmp(const char *haystack, const char *needle) {
    int length;
    if (haystack && needle && strlen(haystack) >= (length = strlen(needle)) && strlen(strstr(haystack,needle)) == length) return 0;
    return 1;
}

int main (int argc, char * argv[]){
    char *a = "file1.gz";
    char *b = "1.gz";
    char *c = NULL;
    char *d = "1.gzabc";

    printf("%s %s = %d\n",a,b,strbcmp(a,b));
    printf("%s %s = %d\n",a,c,strbcmp(a,c));
    printf("%s %s = %d\n",d,b,strbcmp(d,b));

    return 0;
}

根本无法编译。 - lumpidu
对于源代码中的拼写错误表示抱歉。现在已经修正了。 - Roberto Vera Alvarez
1
以下测试与您的实现不兼容:char *e = "1.gzabc1.gz"; printf("%s %s = %d\n",e,b,strbcmp(e,b)); - lumpidu
这段代码无法匹配 haystack 字符串中出现多次的末尾 needle - chqrlie

-3

我建议最好的方法是反转字符串,然后比较前n个字符。

有很多字符串反转函数的示例(甚至Joel都将其引用为标准面试问题),所以只需实现其中一个,然后逐步比较反转后的字符串即可。

编辑以回应负评。好吧,是的,这种方法需要额外的CPU或内存来实现,但是提问者没有表明任何这样的限制,而且他明确要求了一种优雅的解决方案。 反转字符串,然后从前面进行比较比在寻找字符串结尾并向后工作要更加优雅。对于下一个程序员来说,这也更容易理解和维护。


是的,那样做是可行的,但要么需要进行一次内存分配以进行复制,要么需要进行双重反转来撤销损坏。 - plinth
那又怎样?没有迹象表明他在 CPU 或内存受限的情况下操作,并且将字符串翻转以从前面比较要比找到末尾位置并从那里修改逻辑更易于维护。 - Cruachan
无论如何,您都必须找到字符串的结尾才能知道它的长度,因此您将知道如何颠倒它!问题涉及字符串的结尾,所以您必须想办法找到它。 - dreamlax
除了它极其低效的事实,因为您必须两次反转字符串,一次查看它,再次还原它,这意味着对字符串中每个字节进行两次读/写字节访问,仅仅是为了查看最后四个字符。几乎无法理解,完全不优雅。 - dreamlax
1
鉴于没有标准的C89或C99函数来反转字符串,您必须实现和测试此函数以及仅用于检查末尾是否有.foo的函数。与您的解决方案相比,实现任何提供的解决方案都更简单、更容易且需要更少的时间来解决这个问题。 - dreamlax
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接