2014-12-04 7 views
5

У меня есть две строки. Допустим, str1="One Two Three" и str2="two". Я хотел бы знать, есть ли какая-либо функция, которая проверяет соответствие второй строки в первой и возвращает мне указатель на первое вхождение, что-то вроде strstr, но которое не обрабатывает одну и ту же букву, верхнюю или в нижнем регистре, как два разных символа. Для моего примера функция должна найти соответствие для str2 в первой строке, несмотря на верхний регистр "T", "Two". Надеюсь, я поняла. Заранее спасибо. :)Функция strstr() как, которая игнорирует верхний или нижний регистр

+6

Почему вы не просто преобразовать их обоих в нижний/верхний регистр, а затем сравнить их? –

+0

Какой код у вас есть? Какой язык программирования вы используете? – danfuzz

+2

Нет библиотеки 'stristr()' C, но вы можете сделать ее для себя ... –

ответ

20

Из страницы руководства для strstr:

STRSTR(3)   Linux Programmer's Manual   STRSTR(3) 

NAME 
     strstr, strcasestr - locate a substring 

SYNOPSIS 
     #include 

     char *strstr(const char *haystack, const char *needle); 

     #define _GNU_SOURCE 

     #include 

     char *strcasestr(const char *haystack, const char *needle); 

DESCRIPTION 
     The strstr() function finds the first occurrence of the substring needle in 
     the string haystack. The terminating '\0' characters are not compared. 

     The strcasestr() function is like strstr(3), but ignores the case of both arguments. 

RETURN VALUE 
     These functions return a pointer to the beginning of the substring, or NULL if 
     the substring is not found. 


Так что вы ищете является strcasestr.

+2

Моя справочная страница говорит: «Функция strstr() соответствует C89 и C99. Функция strcasestr() является нестандартным расширением». –

+1

Это не в моей библиотеке Visual C. –

+1

Спасибо, это именно то, что я искал. Я не думал об этом в человеке ... В следующий раз я начну с этого. : D – eOf

1

Реализация stristr()

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

char *stristr (const char *str, const char *strSearch) { 
    char *sors, *subs, *res = NULL; 
    if ((sors = strdup (str)) != NULL) { 
     if ((subs = strdup (strSearch)) != NULL) { 
      res = strstr (strlwr (sors), strlwr (subs)); 
      if (res != NULL) 
       res = str + (res - sors); 
      free (subs); 
     } 
     free (sors); 
    } 
    return res; 
} 

int main() 
{ 
    char *str1 = "One Two Three"; 
    char *str2 = "two"; 
    char *sptr = stristr(str1, str2); 
    if (sptr) 
     printf ("Substring is at index %d\n", sptr - str1); 
    return 0; 
} 
+1

Несколько «дорогая» реализация. – Clifford

+0

Это полная реализация, +1 для этого. Поскольку он предназначен для системы, которая не все готова, она имеет смысл реализовать ее только с помощью стандартных функций C и не зависит от других функций, которые могут также иметь не такие системы, как 'strdup()' и 'strlwr () '. – chux

+0

Спасибо ... могли написать 'strdup()' и 'strlwr()' too ;-) –

8

Хотя библиотеки некоторых компилятора C включают расширения с нечувствительны к регистру версий стандартных строковых функций, таких как ГНУ strcasestr(), именование таких функций не нормируется, даже если оно включено.

Одним из способов преодоления отсутствия стандартной реализации, конечно, реализовать свой собственный:

char* stristr(const char* str1, const char* str2) 
{ 
    const char* p1 = str1 ; 
    const char* p2 = str2 ; 
    const char* r = *p2 == 0 ? str1 : 0 ; 

    while(*p1 != 0 && *p2 != 0) 
    { 
     if(tolower((unsigned char)*p1) == tolower((unsigned char)*p2)) 
     { 
      if(r == 0) 
      { 
       r = p1 ; 
      } 

      p2++ ; 
     } 
     else 
     { 
      p2 = str2 ; 
      if(r != 0) 
      { 
       p1 = r + 1 ; 
      } 

      if(tolower((unsigned char)*p1) == tolower((unsigned char)*p2)) 
      { 
       r = p1 ; 
       p2++ ; 
      } 
      else 
      { 
       r = 0 ; 
      } 
     } 

     p1++ ; 
    } 

    return *p2 == 0 ? (char*)r : 0 ; 
} 

тест ниже код выхода:

Two Three 
Two Three 
NULL 
cdefg 
CDEFG 
CdEfG 
NULL 
zzzz 
NULL 

zzzzz 
NULL 

int main(void) 
{ 
    char* test = stristr("One TTwo Three", "two") ; 
    printf("%s\n", test == 0 ? "NULL" : test ) ; 

    test = stristr("One Two Three", "two") ; 
    printf("%s\n", test == 0 ? "NULL" : test ) ; 

    test = stristr("One wot Three", "two") ; 
    printf("%s\n", test == 0 ? "NULL" : test ) ; 

    test = stristr("abcdefg", "cde") ; 
    printf("%s\n", test == 0 ? "NULL" : test ) ; 

    test = stristr("ABCDEFG", "cde") ; 
    printf("%s\n", test == 0 ? "NULL" : test ) ; 

    test = stristr("AbCdEfG", "cde") ; 
    printf("%s\n", test == 0 ? "NULL" : test ) ; 

    test = stristr("1234567", "cde") ; 
    printf("%s\n", test == 0 ? "NULL" : test ) ; 

    test = stristr("zzzz", "zz") ; 
    printf("%s\n", test == 0 ? "NULL" : test ) ; 

    test = stristr("zz", "zzzzz") ; 
    printf("%s\n", test == 0 ? "NULL" : test ) ; 

    test = stristr("", "") ; 
    printf("%s\n", test == 0 ? "NULL" : test ) ; 

    test = stristr("zzzzz", "") ; 
    printf("%s\n", test == 0 ? "NULL" : test ) ; 

    test = stristr("", "zzzz") ; 
    printf("%s\n", test == 0 ? "NULL" : test ) ; 

    test = stristr("AAABCDX","AABC") ; 
    printf("%s\n", test == 0 ? "NULL" : test ) ; 

    return 0; 
} 
+0

@chux: Хорошее место - работает, чтобы исправить. – Clifford

+0

Я тоже попал в угловые случаи, пытаясь действовать как 'strstr (" "," zz "), strstr (" zz "," "), strstr (" "," ")'. – chux

+0

Исправленные '' "," "и' "zzzz", "" 'test cases - возвращают' str1' согласно стандарту 'strstr()'. – Clifford

3

После принимать ответ

Вдохновленный @Clifford и @Weather Vane, подумал, что я попробую свернуть решение, которое использовало бы только стандартные библиотечные функции.

char* stristr3(const char* haystack, const char* needle) { 
    do { 
    const char* h = haystack; 
    const char* n = needle; 
    while (tolower((unsigned char) *h) == tolower((unsigned char) *n) && *n) { 
     h++; 
     n++; 
    } 
    if (*n == 0) { 
     return (char *) haystack; 
    } 
    } while (*haystack++); 
    return 0; 
} 

Несколько сложнее, чтобы соответствовать углу случаи strstr() с входами, как "x","", "","x", "",""

+0

Nice - я исправил мой, чтобы произвести тот же результат, что и ваш. Возможно, вы несколько более лаконичны. Броски не нужны ('tolower()' принимает 'int' - передача символа является безопасным и нормальным), а подпись strstr() в C - это' char * strstr (char *, const char *) ', поэтому приведение в обратном направлении не требуется, если вы используете это. – Clifford

+1

@Clifford C11 7.4 Обработка символов говорит, что «аргумент является« int », значение которого должно быть представлено как« unsigned char »или должно быть равно значению макроса« EOF ». Если аргумент имеет любое другое значение, поведение не определено »Итак, если' char' подписан и 'ch <0', то передача его в' tolower (ch) 'приводит к тому, что' ch' остается отрицательным числом и не попадает в диапазон 'unsigned char' - таким образом, UB. При первом литье '(unsigned char) ch', код заставляет неотрицательное значение передается' tolower() '. – chux

+0

Я задавался вопросом о необходимости неподписанного символа, поскольку буквы находятся ниже значения ASCII 128. Затем я попробовал его с «Über» и «über», и это все равно не работает, потому что, в отличие от английского верхнего/нижнего регистра, значения 129 и 154 ASCII не разделены на 32. –

0

Лучший способ решить эту проблему без написания функции может быть сначала преобразовать как строку в нижний регистр/верхний регистр с помощью «TOLOWER»/«ToUpper», а затем использовать «strstr» :)

+0

Но лучше всего перевести верхний/нижний регистр в функции - так что вы будете писать функцию. Что случилось с написанием функции в любом случае? – Clifford

+0

да .. Я говорил о стандартной библиотеке, поскольку она уже оптимизирована. –

+2

Преобразование строк - лишние накладные расходы - сначала их нужно дублировать, поэтому оптимизация библиотеки становится неактуальной. Ваше предложение - это именно то решение, которое предлагает Weather Vane, и я сделал некоторый анализ производительности на этом и добавил результаты в комментарии. В любом случае это не простой однострочный, так что вам все равно будет лучше писать функцию, как в ответе Weather Vane. Библиотека строк C (и любые расширения) действительно может быть оптимизирована, но обработка строк C в корне неэффективна, а 'strdup()' особенно дорого. – Clifford

1

Вот немного более эффективная версия, которая не вызывает tolower() дважды на символ в строке haystack:

#include <ctype.h> 

char *stristr4(const char *haystack, const char *needle) { 
    int c = tolower((unsigned char)*needle); 
    if (c == '\0') 
     return (char *)haystack; 
    for (; *haystack; haystack++) { 
     if (tolower((unsigned char)*haystack) == c) { 
      for (size_t i = 0;;) { 
       if (needle[++i] == '\0') 
        return (char *)haystack; 
       if (tolower((unsigned char)haystack[i]) != tolower((unsigned char)needle[i])) 
        break; 
      } 
     } 
    } 
    return NULL; 
} 
+0

O() для этого и [that] (https://stackoverflow.com/a/27305359/2410359) являются как «O (h_len * n_len)». Поистине более эффективным будет использование «O (h_len + n_len) подход. – chux

+0

@chux: Я согласен, и я написал * немного более эффективно *. Альтернативные версии с ** O (h_len + n_len) ** имеют стоимость установки, которая в большинстве случаев делает ее более медленной. ** O (h_len * n_len) ** - худший случай, происходящий только для строк патологических аргументов. – chqrlie

+0

Мои тесты показывают, что это значительно быстрее (и такая же функциональность). – chux

1

Если вы находитесь в окнах, вы можете использовать StrStrI. Он работает так же, как и GNU strcasestr, или другой вручную реализованный код stristr в других ответах здесь.

т.д .:

const char needle[] = "and"; 
const char haystack[] = "me and you"; 

const char* pAnd = StrStrIA(haystack, needle); // explicitly call ascii version as windows defaults to wchar 
printf("%s\n", pAnd); // Prints "and you"; 
+0

есть ya go! занял так много времени, чтобы найти это ?! –

Смежные вопросы