Как проверить палиндром в C, игнорируя чувствительность к регистру и пунктуацию?

В настоящее время я пытаюсь написать палиндром, который игнорирует пунктуацию и чувствительность к регистру, 1 с использованием массивов, 2-й с использованием указателей. Моя проблема в том, что я не могу понять, как это сделать. Код, кажется, работает нормально, кроме этого. Я также написал функцию преобразования нижнего регистра в верхний регистр, но я не думаю, что она все равно работает.

Это мой первый код с использованием массивов.

int is_palindrome1(const char phrase[], int length)
{
  int first = phrase[0];
  int last = phrase[length - 1];

  for (length = 0; phrase[length] != '\0'; length++)
  {
    while (last > first)
    {
      if ((phrase[first]) != (phrase[last]))
      {
        return 0;
      }
      last--;
      first++;
    }
    break;
  }
  return 1;
}

Это мой второй код палиндрома с использованием указателей.

int is_palindrome2(const char *phrase, int length)
{
  int i;
  length = strlen(phrase);

  for (i = 0; i < length / 2; i++)
  {
    if (*(phrase + i) != *(phrase + length - i - 1))
    {
      return 0;
    }
  }
  return 1;
}

Вот моя функция нижнего регистра в верхний регистр.

char lower_to_upper(char lower, char upper)
{
  if (lower >= 'a' && lower <= 'z')
  {
    upper = ('A' + lower - 'a');
    return upper;
  }
  else
  {
    upper = lower;
    return upper;
  }
}

person Peter Bui    schedule 24.03.2015    source источник
comment
В выражении 'A' + lower - 'a', выполняющемся для символов, вы, вероятно, получите переполнение при вычислении промежуточных результатов.   -  person Eugene Sh.    schedule 24.03.2015
comment
int first = phrase[0]; int last = phrase[length - 1]; ошибаются.   -  person BLUEPIXY    schedule 24.03.2015
comment
Для преобразования верхнего регистра в нижний см. эта тема   -  person Eugene Sh.    schedule 24.03.2015
comment
В модуле библиотеки ctype int toupper(int c);   -  person Weather Vane    schedule 24.03.2015
comment
@Eugene Sh, касающийся работы с символами, вы, вероятно, получите переполнение, похожее на проблему C ++. В C 'A' является int.   -  person chux - Reinstate Monica    schedule 24.03.2015
comment
@chux Верно. Интересно, как я не знала об этом раньше и моя карьера сохранилась :)   -  person Eugene Sh.    schedule 24.03.2015
comment
@EugeneSh.: Даже в C++ 'A' + lower будет повышен до int.   -  person Bill Lynch    schedule 25.03.2015


Ответы (1)


Так. Давайте сделаем это по шагам.

Простейшая функция is_palindrome:

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

bool is_palindrome(const char *phrase, unsigned length) {
    const char *s = phrase + 0;
    const char *e = phrase + length - 1;

    while (s < e) {
        if (*s != *e)
            return false;
        s += 1;
        e -= 1;
    }
    return true;
}

Добавим сравнения строчных и прописных букв:

Самый простой способ сделать это — преобразовать все допустимые символы в верхний регистр. Похоже, у вас тоже была эта идея, когда вы говорили о функции lower_to_upper().

Единственная проблема в том, что у вашей функции очень странная подпись (почему upper является аргументом?). Таким образом, это легко исправить, используя встроенную функцию toupper(). .

bool is_palindrome(const char *phrase, unsigned length) {
    const char *s = phrase + 0;
    const char *e = phrase + length - 1;

    while (s < e) {
        if (toupper(*s) != toupper(*e))
            return false;
        s += 1;
        e -= 1;
    }
    return true;
}

Как насчет этих других символов (например, пробелов)

В настоящее время. Последняя часть заключается в том, что вы хотите игнорировать пробелы и знаки препинания. Вместо того, чтобы формулировать это таким образом, было бы лучше поговорить о персонажах, которые мы действительно хотим сравнить. Я думаю, что вы хотите сравнивать только буквенно-цифровые символы. Это az, AZ и 0-9. Чтобы проверить, является ли символ одним из них, мы могли бы создать пользовательскую функцию или использовать встроенную функцию isalnum() для этого:

bool is_palindrome(const char *phrase, unsigned length) {
    const char *s = phrase + 0;
    const char *e = phrase + length - 1;

    while (s < e) {
        if (!isalnum(*s)) {
            s++;
        } else if (!isalnum(*e)) {
            e--;
        } else if (toupper(*s) == toupper(*e)) {
            s++;
            e--;
        } else {
            return false;
        }
    }
    return true;
}

Некоторые заключительные мысли:

Обратите внимание, что при каждом проходе цикла мы перемещаем s, e или оба на один шаг. Это гарантирует, что мы в конечном итоге завершим цикл. Наше условие s < e также гарантирует, что как только мы достигнем «середины» строки, мы закончим. Я взял середину в кавычки, потому что для строки "ab a" середина — это второй символ.

Языки - сложные звери:

Английский язык имеет довольно простую кодировку в большинстве (во всех?) системах. Но другие языки не всегда так просты. В комментарии chux была рекомендация по этому поводу:

Локаль, которая может иметь сопоставление «многие к 1» от нижнего к верхнему или наоборот, с использованием кругового пути, если (tolower(toupper(*s)) != tolower(toupper(*e))) обрабатывает это.

Я лично не так обеспокоен, потому что я чувствую, что примерно в тот же момент, когда мы беспокоимся об этом, мы также должны беспокоиться о том, как кодируется текст. Это UTF-8? Это что-то другое? Вероятно, это превосходит ожидания ваших инструкторов.

person Bill Lynch    schedule 24.03.2015
comment
Очень красиво изложено. +1. 2 педантичных замечания: если length==0, то s < e может работать не так, как задумано. Локаль, которая может иметь сопоставление «многие к 1» от нижнего к верхнему или наоборот, с использованием двустороннего обхода if (tolower(toupper(*s)) != tolower(toupper(*e))) обрабатывает это. - person chux - Reinstate Monica; 24.03.2015
comment
Вы можете изменить false на 0, так как OP использует c. - person JuniorCompressor; 24.03.2015
comment
Причина, по которой я сделал функцию для верхнего регистра, а также не использовал функцию isalnum, заключается в том, что мне еще не дали эти инструменты для использования в задании, поэтому я пытаюсь найти способ сделать это, и я подумал, что функция, которую я написал для случая toupper, будет такой же. Когда я попробовал это с isalnum и toupper, я получил ошибку компиляции, которая говорит, что индекс массива имеет тип char. Длина, данная мне, является int, поэтому я должен ввести ее? - person Peter Bui; 25.03.2015
comment
Вы, безусловно, можете самостоятельно реализовать isalnum() и toupper(). Вы уже реализовали toupper(). Ваш первый код выше просто сломан. Вы смешиваете символ и индекс, в котором вы находитесь в строке. Второй код, который у вас есть, выглядит нормально. Но было бы сложно добавить дополнительные функции, когда вы реализуете это таким образом. - person Bill Lynch; 25.03.2015