C++ 中的 C 风格字符串回文检测器(不区分大小写)

C Style String palindrome detector (case insensitive) in C++

我一直在尝试创建一个程序,它从用户那里获取 C 风格的字符串并回答它是否是回文。我已经构建了一个函数 (purg),它取出所有非小写字母(并将大写字母变为小写字母)。另一个是 returns true 或 false 是否为回文。 purg 函数可以按预期打印修改后的字符串(例如 "Race 111 car" 打印为 "racecar"),但是回文函数不会将该修改后的字符串标记为回文,这是怎么回事?

#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
using namespace std;

bool isit(char *test, int u){
   char *well = test;
   bool chk = false;

   for (int i = 0; i<2; i++) {
     if (well[i] != well[u-i-1]) {
       return false;
     }
     cout << well[i];
   }
   return true;
}

void purg(char *ini){
  int x = 0;
  bool answ;
  char *elim = ini;

  for (int i = 0; ini[i] != '[=10=]'; i++) {
    if (ini[i] >= 'A' && ini[i] <= 'Z') {
      elim[i] = ini[i] + 32;
      x++;
    } else if (!(ini[i] >= 'a' && ini[i] <= 'z')) {
      elim[i]='[=10=]';
    } else{
      x++;
    }
    cout << elim[i]; //This reliably prints the answer I expect ("11race car_!" to "racecar")
  }
  answ = isit(&elim[0], x); //Is this passed correctly?
  cout << endl;
  if (answ == true){
    cout << "It is a palindrome." << endl; //(user inputs like "RACecar", "racecar111", "racecar" and "WAAAAW111" are correct)
  } else {
    cout << "No palindrome here..." << endl; //("race car", "1racecar", and "d1o1d" are not, but they print as expected "racecar" and "dod")
  }
}

int main(){
   string str;//I'm not supposed to use C++ strings, should I replace this with char str[512]={}?

   cout<<"Give me a string"<<endl;
   getline(cin,str);

   purg(&str[0]);   
   return 0;
}

快速浏览您的代码后 - 似乎您将所有非字母字符替换为“\0”,然后期望包含随机“\0”字符的字符串通过回文测试,该测试测试字符相等,将 '\0' 视为必须与另一侧的镜像 '\0' 匹配的常规字符。

此外,您将包含 '\0' 字符的全长字符串传递给 isit 函数,但只给出未替换字符的数量作为长度。

您的字符串显示正确打印的原因是,当您打印“\0”时,它什么也没做。用调试器查看 ini 的内容,你会发现它确实被那些被替换的 '\0' 字符弄得乱七八糟。

尝试给它一个不包含任何非字母字符的字符串,如果我是正确的,它应该通过。

首先让我们将您的代码分成两个具有两个不同目的的不同函数,这样我们就可以分别讨论它们:

清除字符串中的非字母

您的代码:

void purge(char *ini) {
  int x = 0;
  bool answ;
  char *elim = ini;

  for (int i = 0; ini[i] != '[=10=]'; i++) {
    if (ini[i] >= 'A' && ini[i] <= 'Z') {
      elim[i] = ini[i] + 32;
      x++;
    } else if (!(ini[i] >= 'a' && ini[i] <= 'z')) {
      elim[i]='[=10=]';
    } else{
      x++;
    }
  }
}

此代码的主要问题:

x 应该做什么?看起来它应该跟踪有效字符的数量,但您从未使用过它。事实上,如果我们运行一个测试:

char s[256] = "a!bc";
purge(s);
ASSERT_EQ("abc", s); // This fails, purge changed the string s into just "a".

我们该如何解决这个问题?

嗯,通过使用 x

void purge(char *str) {
  int x = 0;

  for (int i = 0; ini[i] != '[=12=]'; i++) {
    if (str[i] >= 'A' && str[i] <= 'Z') {
      str[x] = str[i] - 'A' + 'a';
      x++;
    } else if (str[i] >= 'a' && str[i] <= 'z') {
      str[x] = str[i];
      x++;
    }
  }
  // Make sure we null terminate the new string.
  str[x] = '[=12=]';
}

测试字符串是否为回文

您的代码:

bool is_palindrome(char *test, int u){
   char *well = test;
   bool chk = false;

   for (int i = 0; i<2; i++) {
     if (well[i] != well[u-i-1]) {
       return false;
     }
     cout << well[i];
   }
   return true;
}

代码问题:

  1. 错误的变量名。 u 应该是什么? well 应该是什么?
  2. 为什么你只从 i=0..2 开始循环?

我们如何解决这个问题...

bool is_palindrome(char *str, int str_length) {
  for (int i = 0; i < str_length / 2; i++) {
    if (str[i] != str[str_length - i - 1]) {
      return false;
    }
  }
  return true;
}

其他想法

通过将代码重写为两个单独的函数,我们可以开始向这段代码添加测试。例如,我们可以使用 google 的单元测试基础设施来做类似的事情:

TEST(MyTests, Purge_Nothing) {
  char a[256] = "abc";
  purge(a);
  EXPECT_EQ(std::string("abc"), a);
}

TEST(MyTests, Purge_Non_Letters_At_Front) {
  char a[256] = "!abc";
  purge(a);
  EXPECT_EQ(std::string("abc"), a);
}

TEST(MyTests, Purge_Non_Letter_In_Middle) {
  char a[256] = "ab!c";
  purge(a);
  EXPECT_EQ(std::string("abc"), a);
}

TEST(MyTests, Purge_Non_Letters_At_End) {
  char a[256] = "abc!";
  purge(a);
  EXPECT_EQ(std::string("abc"), a);
}

TEST(MyTests, Purge_Uppercase) {
  char a[256] = "Abc!";
  purge(a);
  EXPECT_EQ(std::string("abc", a);
}

TEST(MyTests, Palindrome) {
  EXPECT_TRUE(is_palindrome("abcba");
  EXPECT_TRUE(is_palindrome("abba"));
  EXPECT_TRUE(is_palindrome("aba"));
  EXPECT_TRUE(is_palindrome("aa"));
  EXPECT_TRUE(is_palindrome("z"));
  EXPECT_TRUE(is_palindrome(""));
  EXPECT_FALSE(is_palindrome("abcda");
  EXPECT_FALSE(is_palindrome("abda");
  EXPECT_FALSE(is_palindrome("abd");
  EXPECT_FALSE(is_palindrome("ad");
}

用于回文测试的不区分大小写函数的 C 示例。您可以像在 C++ 代码中一样使用它。

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

int is_palindrome(const char * str) {
    const char * tail = str + strlen(str) - 1;

    for ( ; str < tail && toupper(*str) == toupper(*tail); ++str, --tail )
        ;

    return str >= tail;
}