Удаление знаков препинания и пробелов из строки в c?

Это для домашнего задания в школе. Я не прошу правильных ответов, просто подтолкнуть в правильном направлении. Объяснение того, почему это происходит не так, было бы здорово, а также объяснение правильного метода. Что должна делать эта программа на C, так это читать пользовательский ввод без пробелов и знаков препинания и присваивать его строке массива символов. Затем этот массив следует передать в палиндром функции. Палиндром должен иметь длину строки, и если он равен 1 или 0, вернуть TRUE или 1, иначе двигаться дальше и проверить первый и последний символ строки. Если они совпадают, извлеките 2-й и 2-й до последнего символов, а также все символы между ними и передайте их в палиндром функции.

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

#define TRUE 1
#define FALSE 0
typedef int Bool;

Bool palindrome(char str[]);
main()
{
char string[1000], ch;
int i = 0;

printf("Enter a message: ");
while((ch = getchar()) != '\n'){
  if(isspace(ch)==FALSE || ispunct(ch)==FALSE);
    string[i] = tolower(ch);
    i++;
}

string[i] = '\0';

printf("\n");
if(palindrome(string))
  printf("Palindrome\n");
else
  printf("Not a palindrome\n);

return 0;
}

Bool palindrome(char str[])
{
   int length = strlen(str);
   if((length == 1) || (length == 0))
     return TRUE;
   else
   {
     if((str[0] == str[length - 1])
       {
         char str_new[length-1];
         int i, j;
         for(i = 1, j = 0; str[i]!=str[length-1]; i++, j++)
           str_new[j] = str[i];

         str_new[i] = '\0';
         palindrome(str_new);
       }
       else
         return FALSE;

   }
}

Независимо от того, какой ввод, он всегда печатает, что заданная строка не является палиндромом. Например, когда я ввожу

Он жил как дьявол, а?

он распечатывает

Не палиндром

Также, когда я редактировал программу, чтобы проверить, что было в строке массива, используя предыдущий ввод, это было

Он жил как дьявол, а?

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

РЕДАКТИРОВАТЬ:
Я проверил, какое значение в массиве символов, строка, было. Я говорю это перед последней цитатой.


person thad    schedule 23.03.2013    source источник
comment
Совет. Перед передачей очищенной строки в palindrome() распечатайте ее. Тогда вы узнаете, правильно ли вы его продезинфицировали.   -  person alexis    schedule 23.03.2013
comment
if (!isspace(ch) && !ispunct(ch)) или еще лучше: if (isletter(ch))   -  person alexis    schedule 23.03.2013
comment
@user Я думаю, что на ваш вопрос дан ответ: meta.stackexchange.com/questions/5234   -  person David Heffernan    schedule 23.03.2013


Ответы (3)


if(isspace(ch)==FALSE || ispunct(ch)==FALSE);

Это твоя ошибка. Во-первых, в конце не должно быть точки с запятой (;).

Во-вторых, вы не должны использовать ИЛИ, вы должны использовать И, потому что вы хотите убедиться, что вы фильтруете все, кроме алфавита:

if(isspace(ch)==FALSE && ispunct(ch)==FALSE)

Также:

for(i = 1, j = 0; str[i]!=str[length-1]; i++, j++)

Здесь логическое выражение неверно. Вы должны оценивать j:

for(i = 1, j = 0; j < length - 1; i++, j++)

Наконец, ваше позиционирование оператора i++ при добавлении символов к новой строке неверно. Отодвиньте его назад, чтобы компилятор знал, что он должен быть частью тела цикла while и находиться вне блока if.

person user123    schedule 23.03.2013

Посмотрите здесь...

while((ch = getchar()) != '\n'){
  if(isspace(ch)==FALSE || ispunct(ch)==FALSE);
    string[i] = tolower(ch);
    i++;
}

Обратите внимание ';' в конце оператора if. Что ';' приводит к тому, что string[i] = tolower(ch) всегда выполняется. Кроме того, ваша логика неверна, вы хотите, чтобы код выполнялся, если символ не является пробелом И это не знак препинания.

Кроме того, следите за своим отступом. i++ также должен быть внутри оператора if, но вокруг него отсутствуют фигурные скобки. Таким образом, даже если вы удалите ';', i++ все равно будет выполняться всегда. Так...

while((ch = getchar()) != '\n'){
  if(isspace(ch)==FALSE && ispunct(ch)==FALSE)
  {
    string[i] = tolower(ch);
    i++;
  }
}

Или... еще лучше...

while((ch = getchar()) != '\n'){
  if(isspace(ch)==FALSE && ispunct(ch)==FALSE)
    string[i++] = tolower(ch);
}

Комментарий к стилю... часто полезно иметь единую точку выхода из функций для обслуживания и удобочитаемости. Другие могут рассуждать по-другому, но это было жесткое правило, которому я следовал последние 30 лет, работая в Министерстве обороны. Посмотрите на это для удобочитаемости и посмотрите, имеет ли это больше смысла для вас.

Bool palindrome(char str[])
{
   Bool result = TRUE;
   int length = strlen(str);

   if( length > 1 && str[0] == str[length-1] )
   {
     char str_new[length-1];
     int i, j;

     for(i = 1, j = 0; str[i]!=str[length-1]; i++, j++)
        str_new[j] = str[i];

     str_new[i] = '\0';
     result = palindrome(str_new);
   }

   return result;
}

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

Bool palindrome(char str[])
{
    Bool result = TRUE;
    int length = strlen(str);

    if( length > 1 && str[0] == str[length-1] )
    {
       str[length-1] = '\0';
       result = palindrome(&str[1]);
    }

    return result;
}
person K Scott Piel    schedule 23.03.2013
comment
Логика в if неверна, а функция палиндрома слишком сложна. - person David Heffernan; 23.03.2013
comment
Итак, теперь мы рассказали вам, как исправить if, и вы это сделали. Отличная работа. Но ваша функция palindrome просто не работает. На всю жизнь я не могу понять, почему за этот ответ проголосовали. - person David Heffernan; 23.03.2013

Некоторые очевидные моменты:

  • Код в вопросе не компилируется.
  • Ваше основное объявление не является стандартным.
  • Оператор if содержит ошибочную точку с запятой в конце строки.
  • Логика в вашем операторе if неверна. Логический или тест всегда будет оцениваться как истина, поскольку символ не может быть одновременно пробелом и пунктуацией.
  • Ваша функция проверки палиндрома намного сложнее, чем должна быть.

Ключевое изменение, которое нужно внести, заключается в том, что ваш оператор if должен выглядеть так:

if (!isspace(ch) && !ispunct(ch))

Полная рабочая программа выглядит так:

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

#define TRUE 1
#define FALSE 0
typedef int Bool;

Bool palindrome(char str[]);

int main(void)
{
    char string[1000], ch;
    int i = 0;

    printf("Enter a message: ");
    while((ch = getchar()) != '\n'){
        if (!isspace(ch) && !ispunct(ch))
        {
            string[i] = tolower(ch);
            i++;
        }
    }

    string[i] = '\0';
    printf("string = %s\n", string);
    if(palindrome(string))
        printf("Palindrome\n");
    else
        printf("Not a palindrome\n");

    return 0;
}

Bool palindrome(char str[])
{
   int left = 0;
   int right = strlen(str)-1;
   while (left<right)
   {
       if(str[left] != str[right])
           return FALSE;
       left++;
       right--;
   }
   return TRUE;
}

Вот результат:

Enter a message: He lived as a devil, eh?
string = helivedasadevileh
Palindrome
person David Heffernan    schedule 23.03.2013
comment
Основное утверждение совершенно законно, если вам не нужны аргументы командной строки. - person K Scott Piel; 23.03.2013
comment
@KScottPiel Я отсылаю вас к этому вопросу: stackoverflow.com/questions/2108192/ - person David Heffernan; 23.03.2013