【问题标题】:Eliminate punctuations and whitespace消除标点符号和空格
【发布时间】:2019-05-09 02:17:25
【问题描述】:

我是 C++ 编程新手,想编写一个具有以下要求的程序:

给定一个文本由

  • 单词
  • 信件
  • 数字
  • 标点符号和
  • 空格。

过滤掉所有不在0..9a..zA..Z 范围内的字符。

这意味着当我输入时:

The quick brown fox jumps over the lazy dog!

输出将是:

Thequickbrownfoxjumpsoverthelazydog

我输入了以下代码并尝试运行它,结果很好。但是,当我将它提交到另一个 c++ 平台进行有效性检查时,并没有生成输出。

我很困惑...如果可以,请提供帮助。非常感谢大家。

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

int main()
{
    string line;
    getline(cin, line);
    for (int i = 0; i < line.size(); ++i)
    {
        if (!((line[i] >= 'a' && line[i] <= 'z') || (line[i] >= 'A' && line[i] <= 'Z') || (line[i] >= '0' && line[i] <= '9')))
        {
            line[i] = '\0';
        }
    }
    cout << line;
    return 0;
}

【问题讨论】:

  • 您没有删除任何字符。你替换\0,它通常有一个特殊的含义——它标志着字符串的结束。您的“其他 C++ 平台”可以通过这种方式解析字符串,并得出结论认为它收到了空字符串。改用 if 中的 erase(i, 1)
  • 你误以为line[i] = '\0'; 会删除一个字符。它没有,它只是用另一个字符替换一个字符。 std::string 有一个方法 erase 用于擦除字符,尝试使用它。
  • 你的意思是改行[i] = '\0];擦除(i,1)?我不太明白你们的意思

标签: c++ algorithm string-parsing stdstring input-filtering


【解决方案1】:

如果您想删除 lettersdigits 以外的字符,更好的选择是使用erase–remove idiom

  1. 使用 std::isalnum 检查字符串中的字符是 alphabet 还是 数字。如果将其打包成一元谓词(lambda 函数),则可以应用于以下算法函数。
  2. 使用 std::remove_if, 和上述谓词,收集所有字符 字符串,必须删除。
  3. 最后,使用 std::string::erase 删除所有已收集的字符 std::remove_if

如下所示: See a demo here

#include <cctype>     // std::isalnum
#include <algorithm>  // std::remove_if

std::string str{ "The quick brown fox jumps over the lazy dog!" };

// predicate to check the charectors
const auto check = [](const char eachCar)->bool { return !std::isalnum(eachCar); };

// collect the chars which needed to be removed from the string
const auto charsToRemove = std::remove_if(str.begin(), str.end(), check);

// erase them out
str.erase(charsToRemove, str.end());

免责声明:上述解决方案并未涵盖 OP 的关注点(@john 在his answer 中已经很好地解释了这一点),但它可能对未来的读者有所帮助。

【讨论】:

  • 那么你认为OP有什么机会理解上面的代码?
  • 好吧,我想这是一个常见问题,您是为 OP 还是为其他可能正在阅读的人回答这个问题。就我个人而言,当它是这样的基本内容时,我总是回答 OP。
  • @john 是的...我更喜欢总是回答关注问题。当谈到替代快捷方式(即使用 C++ 算法)时,我宁愿使用它们来回答。正如您所提到的,对于未来的读者来说,这可能会有所帮助。有时,OP 甚至可以告知自己可用的标准设施,他/她将要改造什么。(恕我直言)
【解决方案2】:

您的代码只是将一个字符替换为另一个字符。从字符串中删除字符的简单方法是使用erase 方法。像这样的

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

int main() 
{
    string line;
    getline(cin, line);
    for (int i = 0; i < line.size(); )
    {
        if (!((line[i] >= 'a' && line[i]<='z') || (line[i] >= 'A' && line[i]<='Z')||(line[i] >= '0' && line[i]<='9')))
        {
            line.erase(i, 1);
        }
        else
        {
            ++i;
        }
    }
    cout << line; 
    return 0;
}

请注意,当我们不删除字符时,代码只会在i 中添加一个,否则您会跳过删除后的字符,因为字符串现在短了一个。

【讨论】:

  • 感谢您的回答。你很棒,对于像我这样的人来说,答案很容易理解。但是,还有一个问题是输出中是否缩进了一个空格?我应该如何删除缩进?
  • @ChunTsz 我不确定,您看到的输入和输出是什么?上面的代码很容易有bug,我没有测试过。
  • @john 我已经解决了这个问题,但是另一个问题出来了,我无法处理..例如,如果输入是 : abcdefg /n hijklmn ,那么现在程序只输出 abcdefg 但没有hijklmn 附加在前者后面。我应该如何修改代码?我能得到一些提示吗?
  • 你需要读多行,getline 只读一行,所以你需要围绕你的代码进行某种循环。例如。 while (getline(cin, line)) { ... }
  • 尝试这两种方法,并思考运行程序时的区别。编程不是魔法,你可以自己解决。
【解决方案3】:

\0 是字符串的结尾,所以当你使用它时,你会在第一次出现时切断你的字符串。

您最好从数组中删除该字符,但我建议您从末尾回到开头:

伪代码:

for i = size(line)-1 back to i = 0:
  if line[i] in ('a'-'z', 'A'-'Z', ...):
    for j = i to size(line)-1:
      line[j] = line[j+1]
   reduce_by_the_last_character(line)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-20
    • 2019-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-09
    相关资源
    最近更新 更多