当然解决方案是使用std::getline 读取整行,包括空格。
我不明白你的行if(isspace(s[i])){cout<<"n";},因为在你显示的输出示例中,你想显示空格而不是“n”。我想这是一个错字,应该是“”。
无论如何。使用std::getline 你的函数看起来像
#include <iostream>
#include <string>
int main() {
// We need to operate on a given number of test cases
size_t numberOfTestCases{}; std::cin >> numberOfTestCases;
// Handle all test cases
while (numberOfTestCases--) {
// Read a complete line with text
std::string line{}; std::getline(std::cin, line);
// In case of space or vowel, print that
for (const char c : line)
if ((c == 32) or ((0x208222 >> (c & 0x1f)) & 1)) std::cout << c;
std::cout << '\n';
}
return 0;
}
因为我看到了一些带有“测试用例”的东西,我猜你是在一些不神圣的“竞赛编程”网站上。
这就是为什么我使用条件((0x208222 >> (c & 0x1f)) & 1) 来检查一个字符是否是元音。这已经有几十年的历史了。对于这样的网站来说已经足够了。
如果有人对它的工作原理感兴趣,请发表评论,我将编辑答案并解释它。
编辑
根据要求,我将解释 for 循环。首先,我们有一个如此基于范围的 for 循环。和写法一样:
for (int i=0; i < line.length(); ++i) {
const char c = line[i];
. . .
}
然后你可以看到,我们首先检查字符 c 是否等于 32。32 是空格的 ASCII 码。你可以看到这个here。
那么,现在,如何检查一个字符是否是元音。
如果我们使用 ASCII 码对字母进行编码,那么我们将看到以下内容:
我们看到大写和小写字母的 ASCII 码只是低 5 位不同。
所以,如果我们用 0x1F 屏蔽 ASCII 码,所以char c{'a'}; unsigned int x{c & 0x1F},我们将得到 1 到 26 之间的值。
所以,我们可以为每个字母计算一个 5 位的值。
如果我们现在用 1 标记所有元音,我们可以构建一个由 32 位(无符号整数)组成的二进制数,并在元音为真的每个位置设置一个位。然后我们得到类似的东西
Bit position
3322 2222 2222 1111 1111 1100 0000 0000
1098 7654 3210 9876 5432 1098 7654 3210
Position with vowels:
0000 0000 0010 0000 1000 0010 0010 0010
这个数字可以转换为0x208222。
如果我们现在想知道,如果一个字母(无论是大写还是小写)是元音,那么我们从字符中屏蔽掉不必要的位( C & 1F )并将二进制数转移到与生成的字母代码一样多的位置。如果然后该位设置在 LSB 位置,则我们有一个元音。这已经有几十年的历史了。
示例:字符“e”。 ASCII 码是 101。用 1F 屏蔽会变成 5。然后我们将数字 0x208222(等于0000 0000 0010 0000 1000 0010 0010 0010)向右移动这 5 个位置,得到0000 0000 0000 0001 0000 0100 0001 0001。并且设置了带有“e”标记的最低位。因此,它是一个元音。
啊哈。不是那么容易,但适用于 ASCII 编码的字母。
顺便说一句,它也适用于其他字符选择。
结果是:
auto isVowel = [](char c) { return (0x208222 >> (c & 0x1f)) & 1; };
酷。 . .