Я написал функцию, которая берет одну строку и делает последний символ каждого слова прописным, а остальные - строчными. Что с этим не так? - PullRequest
1 голос
/ 04 августа 2020

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

Мой код:

#include <string.h>
char* rcapitalize(char* p)
{
    char space = 32,tab = 9;
    int len = strlen(p);
    for (int i = 0;i<len;i++)
    {
        if (p[i]>='a' && p[i]<='z' && (p[i+1])==space ||p[i]>='a' && p[i]<='z' && (p[i+1])=='\0' ||p[i]>='a' && p[i]<='z' && (p[i+1])==tab)
        {
            p[i]=p[i]-32;
        }
        else if (p[i]>='A' && p[i]<='Z' && (p[i+1])!=tab ||p[i]>='A' && p[i]<='Z' && (p[i+1])!=space || p[i]>='A' && p[i]<='Z' && (p[i+1])!='\0')
        {
            p[i] = p[i]+32;
        }
        
        
    }
    return p;
}
Input: "a FiRSt LiTTlE TESt"
Return Value: "A firsT littlE tesT"
My return value: "A firsT little tesT"

Почему 'E' в слове делается в нижнем регистре "littlE"?

Ответы [ 5 ]

2 голосов
/ 04 августа 2020

Слово "LiTTlE" - единственное слово в строке, которое содержит последнюю букву в верхнем регистре.

Первое подвыражение оператора else if

p[i]>='A' && p[i]<='Z' && (p[i+1])!=tab

всегда будет оцениваться как истина, потому что символ p[i+1] действительно не равен tab. Таким образом, полное выражение всегда будет истинным.

Вместо логического оператора ИЛИ вы должны использовать логический оператор И в полном выражении этого оператора else if.

Например, это может выглядеть как

else if ( p[i] >= 'A' && p[i] <= 'Z' && p[i+1] != tab && p[i+1] != space && p[i+1] != '\0' )

Тем не менее программа выглядит плохо. Это не будет работать правильно, например, если вместо таблицы символов ASDII будет использоваться таблица символов EBCDI C.

Для начала не используйте magi c числа типа 32. Используемые логические выражения слишком сложные. Вызов strlen является избыточным.

Вот демонстрационная программа, которая показывает, как можно написать функцию.

#include <stdio.h>
#include <ctype.h>

char * rcapitalize( char *s )
{
    for ( char *p = s; *p; ++p )
    {
        unsigned char c1 = p[0], c2 = p[1];
        
        if ( isalpha( c1 ) )
        {
            if ( isspace( c2 ) || c2 == '\0' )
            {
                *p = toupper( c1 );
            }
            else if ( isupper( c1 ) )
            {
                *p = tolower( c1 );
            }
        }
    }
    
    return s;
}

int main(void) 
{
    char s[] = "a FiRSt LiTTlE TESt";
    
    puts( rcapitalize( s ) );
    
    return 0;
}

Результат программы:

A firsT littlE tesT
2 голосов
/ 04 августа 2020

В этой функции есть несколько ошибок.

Но это условие, непосредственно вызывающее ошибку, заключающуюся в строчной букве «E».

Это должно соответствовать заглавным буквам не в конце слова правильно? Но вместо этого он соответствует всем заглавным буквам.

else if (p[i]>='A' && p[i]<='Z' && (p[i+1])!=tab ||p[i]>='A' && p[i]<='Z' && (p[i+1])!=space || p[i]>='A' && p[i]<='Z' && (p[i+1])!='\0'

Когда выполнение доходит до состояния, которое не удается p[i] == 'E', тогда (p[i+1])!='\0' истинно (даже если (p[i+1])!=space ложно)

0 голосов
/ 04 августа 2020

Ваше условие if не делает то, что вы хотите.

Ваши проверки символов являются «действительными», потому что это ASCII, но полная версия будет состоять в использовании функции is_lower, is_upper, toupper, tolower, указатели как показывает другой ответ

, но я думаю, что это учебное упражнение для новичков, поэтому можно использовать ASCII

char* rcapitalize(char *p) {
  char space = 32, tab = 9;
  int len = strlen(p);

  for (int i = 0; i < len; i++) {
    if (i + 1 <= len && (p[i + 1] == space || p[i + 1] == tab || p[i + 1] == '\0')) {
      if (p[i] >= 'A' && p[i] <= 'Z')
        p[i] += 32;
      if (p[i] >= 'a' && p[i] <= 'z')
        p[i] -= 32;
    }
  }
  return p;
}
0 голосов
/ 04 августа 2020

Как указано в комментарии:

  • ваши условия if слишком сложны, вы должны попытаться разложить их на множители
  • для ваших тестов, вы должны использовать C стандартные функции, такие как isspace ()
  • для вашей обработки вы должны использовать C стандартные функции, такие как toupper ()

Упростив условия if, вы увидите, что (p[i+1]) != tab || (p[i+1]) != space всегда истинно.

Согласно всему этому, вот упрощенная версия вашей функции:

char* rcapitalize(char* p) {
    size_t len = strlen(p);

    for (size_t i = 0; i < len; i++) {
        if (p[i + 1] == '\0' || isspace(p[i + 1])) {
            p[i] = toupper(p[i]);
        } else {
            p[i] = tolower(p[i]);
        }
    }

    return p;
}
0 голосов
/ 04 августа 2020

Его можно упростить, используя функции для выполнения некоторых обычных вещей (только ASCII):

int myisspace(int c)
{
    if(c == ' ' || c == '\t') return 1;
    return 0;
}

int myisupperletter(int c)
{
    if((c >= 'A' && c <= 'Z')) return 1;
    return 0;
}

int myislowerletter(int c)
{
    if((c >= 'a' && c <= 'z')) return 1;
    return 0;
}


int mytolower(int c)
{
    if(myisupperletter(c)) c += 'a' - 'A';
    return c;
}

int mytoupper(int c)
{
    if(myislowerletter(c)) c -= 'a' - 'A';
    return c;
}


char* rcapitalize(char* p)
{
    
    for(char *wrk = p; *wrk; wrk++)
    {
        if(myisspace(wrk[1]) || !wrk[1]) *wrk = mytoupper(*wrk);
        else *wrk = mytolower(*wrk);
    }
    return p;
}

int main()
{
    char r[] = "  aa      -----  FiRSt LiTTlE TESt   ";
    printf("%s\n", rcapitalize(r));
}

https://godbolt.org/z/ssnMPY

или вы можете использовать функции из стандартная библиотека

char* rcapitalize(char* p)
{
    for(char *wrk = p; *wrk; wrk++)
    {
        if(isspace(wrk[1]) || !wrk[1]) *wrk = toupper(*wrk);
        else *wrk = tolower(*wrk);
    }
    return p;
}

Использование

int main()
{
    char r[] = "  aa        FiRSt LiTTlE TESt   ";
    printf("%s\n", rcapitalize(r));
}

А здесь вы можете сами протестировать и поиграть: https://godbolt.org/z/a4xr4G

...