Как сравнить концы строк в C? - PullRequest
33 голосов
/ 13 апреля 2009

Я хочу убедиться, что моя строка заканчивается на ".foo". Я использую C, язык, с которым я не совсем знаком. Лучший способ сделать это - ниже. Любой гуру хочет убедиться, что я делаю это элегантно и мудро?

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

Ответы [ 18 ]

46 голосов
/ 13 апреля 2009

Не вызывайте strlen более одного раза для каждой строки.

int EndsWith(const char *str, const char *suffix)
{
    if (!str || !suffix)
        return 0;
    size_t lenstr = strlen(str);
    size_t lensuffix = strlen(suffix);
    if (lensuffix >  lenstr)
        return 0;
    return strncmp(str + lenstr - lensuffix, suffix, lensuffix) == 0;
}

int EndsWithFoo(const char *str) { return EndsWith(str, ".foo"); }

EDIT: добавлена ​​проверка NULL для педантичных. Для ультрапедантичного, обсудите, должен ли он возвращать ненулевое значение, если и str, и суффикс имеют значение NULL.

8 голосов
/ 13 апреля 2009
int EndsWithFoo( char *string )
{
  string = strrchr(string, '.');

  if( string != NULL )
    return( strcmp(string, ".foo") );

  return( -1 );
}

Вернет 0, если заканчивается ".foo".

7 голосов
/ 13 апреля 2009

У меня сейчас нет доступа к компилятору, так что может кто-нибудь сказать мне, если это работает?

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

int EndsWithFoo(const char* s);

int
main(void)
{
  printf("%d\n", EndsWithFoo("whatever.foo"));

  return 0;
}

int EndsWithFoo(const char* s)
{
  int ret = 0;

  if (s != NULL)
  {
    size_t size = strlen(s);

    if (size >= 4 &&
        s[size-4] == '.' &&
        s[size-3] == 'f' &&
        s[size-2] == 'o' &&
        s[size-1] == 'o')
    {
      ret = 1;
    }
  }

  return ret;
}

В любом случае, убедитесь, что параметр квалифицирован как const, он говорит всем (включая компилятор), что вы не собираетесь изменять строку.

3 голосов
/ 14 апреля 2009

Если вы можете изменить сигнатуру своей функции, попробуйте изменить ее на

int EndsWith(char const * str, char const * suffix, int lenstr, int lensuf);

Это приведет к более безопасному, более многократно используемому и более эффективному коду:

  1. Добавленные квалификаторы const гарантируют, что вы не ошибочно измените входные строки. Эта функция является предикатом, поэтому я предполагаю, что она никогда не будет иметь побочных эффектов.
  2. Суффикс для сравнения передается в качестве параметра, поэтому вы можете сохранить эту функцию для последующего повторного использования с другими суффиксами.
  3. Эта подпись даст вам возможность передать длины строк, если вы их уже знаете. Мы называем это динамическое программирование .

Мы можем определить функцию следующим образом:

int EndsWith(char const * str, char const * suffix, int lenstr, int lensuf)
{
    if( ! str && ! suffix ) return 1;
    if( ! str || ! suffix ) return 0;
    if( lenstr < 0 ) lenstr = strlen(str);
    if( lensuf < 0 ) lensuf = strlen(suffix);
    return strcmp(str + lenstr - lensuf, suffix) == 0;
}

Очевидным контраргументом для дополнительных параметров является то, что они подразумевают больше шума в коде или менее выразительный код.

2 голосов
/ 13 апреля 2009

Проверенный код, включает в себя тест:

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

int ends_with_foo(const char *str)
{
    char *dot = strrchr(str, '.');

    if (NULL == dot) return 0;
    return strcmp(dot, ".foo") == 0;
}

int main (int argc, const char * argv[]) 
{
    char *test[] = { "something", "anotherthing.foo" };
    int i;

    for (i = 0; i < sizeof(test) / sizeof(char *); i++) {
        printf("'%s' ends %sin '.foo'\n",
               test[i],
               ends_with_foo(test[i]) ? "" : "not ");
    }
    return 0;
}
2 голосов
/ 13 апреля 2009

strlen(".foo") не требуется. Если вы действительно хотите иметь гибкость, вы можете использовать sizeof ".foo" - 1 - постоянную времени компиляции.

Кроме того, проверка нулевой строки была бы хороша.

1 голос
/ 27 мая 2015

Извините, я немного опоздал на вечеринку. Не могли бы вы сделать что-нибудь с простой математикой указателя?

char* str = "hello.foo"; //this would be string given

int x = 4; //.foo has 4 characters

int n = strlen(str)- x; //where x is equal to suffix length

char* test = &str[n]; //do some pointer math to find the last characters

if(strcmp(test, ".foo") == 0){
    //do some stuff
}// end if

Указатели на символы работают, указывая на первый символ в их массиве. Поэтому, когда вы делаете это, вы устанавливаете первый символ теста как «.» в «.foo» (если это то, что он содержит). Вот почему вам не нужно выделять для него память, поскольку она просто указывает на уже существующий массив символов.

0 голосов
/ 07 января 2019

Это самый эффективный (для компьютера) ответ, который вы найдете здесь.

int endsWith(const char *string,const char *tail)
{

    const char *s1;

    const char *s2;

    if (!*tail)
        return 1;
    if (!*string)
        return 0;
    for (s1 = string; *s1; ++s1);
    for (s2 = tail; *s2; ++s2);
    if (s1 - string < s2 - tail)
        return 0;
    for (--s1, --s2; *s1 == *s2 && s2 >= tail; --s1, --s2);
    if (s2 < tail)
        return 1;
    else
        return 0;
}
0 голосов
/ 09 сентября 2018
int strends(char* str, char* end){
    return strcmp(str + strlen(str) - strlen(end), end) == 0;
}

Я обнаружил, что это самый простой способ достижения результата.

0 голосов
/ 24 июля 2016

Я всегда проверяю строковые функции glib, у них есть все виды полезных битов. Функция проверки суффикса уже существует.

gchar * str;

if (!g_str_has_suffix(str)) {
    return FALSE;
}

Я немного новичок в C, поэтому я прошу прощения, если это не на 100% ... но для меня это выглядит как надежная оговорка!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...