我一直在练习不同的方法来过滤从nlohmann::json对象到std::字符串中不需要的垃圾字符,我刚刚完成了以下函数,给了我一个很好的结果(当然忽略了我写的是初学者的草率代码(:
//This string is what I'm testing with as input.
std::string initial = "EA/1n n $9.34n n ";
std::string filter(std::string s) {
std::stringstream ss(s);
char c;
std::string final_string = "";
while (ss >> c) {
if (c == ' ') {
char temp_c = c;
while (ss >> c) {
if (c == ' ') {
continue;
}
else {
final_string += temp_c;
break;
}
}
}
else {
final_string += c;
}
}
return final_string;
}
//this is string that is produced when s is returned to main
result = "EA/1 $9.34"
我不知道为什么"\n"one_answers"\t"也被过滤掉了,尽管我在这一步的测试中只针对"。如果需要,我可以提供一张Visual Studio 2019在initial
中显示的具体内容的分解照片。任何见解都将是最有帮助的,因为在接下来的几天里,我将研究其他具有类似化妆的字符串。
已编辑:我已将函数返回的变量从s
更改为final_string
。很抱歉造成混乱。
编辑2:我选择了雷米·勒博的答案,因为这让我意识到我的过滤确实根本不起作用,这让我学会了在占用你们的时间之前进行更彻底的调试。我找到SO的结果正是我想要的,这让我相信我的代码在某种程度上更有效,因此我感到困惑。我现在会更清楚的哈哈。无论如何,雷米的回答帮助我解决了我想知道的问题,并为我的前进提供了很好的建议。
在此代码中:
while (ss >> c) {
if (c == ' ') {
if
永远不会计算为true
,因为默认情况下operator>>
会跳过前导空格,其中包括空格、制表符和换行符。所以c
永远不会像' '
那样是空白字符。
任一:
- 使用
std::noskipws
,就像@WhozCraig在评论中建议的那样:
while (ss >> std::noskipws >> c)
- 使用不跳过空白的
std::istream::get()
:
while (ss.get(c))
也就是说,您的代码中还有其他错误。
您返回的是未修改的s
,而不是准备好的final_string
。
看起来您的内部while
循环正在尝试将2个以上空间的运行最小化为1个空间用于输出。这很好,只是丢失了结束检测到的运行的字符。
试试类似的东西:
std::string filter(const std::string &s) {
std::istringstream iss(s);
char c;
std::string final_string;
while (iss.get(c)) {
if (c == ' ') {
while (iss.get(c)) {
if (c != ' ') {
final_string += ' ';
final_string += c;
break;
}
}
}
else {
final_string += c;
}
}
return final_string;
}
最后,当以这种方式构建新的std::string
时,通常使用std::ostringstream
而不是operator+=
更有效(除非您在前面reserve()
是std::string
(,例如:
std::string filter(const std::string &s) {
std::istringstream iss(s);
char c;
std::ostringstream final_string;
while (iss.get(c)) {
if (c == ' ') {
while (iss.get(c)) {
if (c != ' ') {
final_string << ' ' << c;
break;
}
}
}
else {
final_string << c;
}
}
return final_string.str();
}
问题出现在std::stringstream::operator>gt;((函数。我确信函数中转义了'\n'、'\t\t和空格。下面的代码将输出与您已经得到的结果相同的结果。
while (ss >> c) {
final_string += c;
}
return final_string
使用基本代码而不是字符串流会更好,如下所示。
std::string filter(std::string s) {
char c;
int i = 0;
std::string final_string = "";
do{
c = s[i];
if (c != ' ') {
final_string += c;
}
i++;
} while (c != 0);
return final_string;
}
假设目的是将连续运行的选项卡和空格压缩到一个空间,但保留新行,我可能会做一些不同的事情。
#include <locale>
#include <iostream>
#include <algorithm>
#include <iterator>
#include <sstream>
#include <numeric>
class my_ctype : public std::ctype<char> {
mask my_table[table_size];
public:
my_ctype(size_t refs = 0) : std::ctype<char>(&my_table[0], false, refs){
std::copy_n(classic_table(), table_size, my_table);
my_table['n'] = mask();
}
};
int main() {
std::stringstream input("EA/1n n $9.34n n ");
std::locale ss(std::locale::classic(), new my_ctype);
input.imbue(ss);
std::string word;
while (input >> word)
std::cout << '"' << word << ""n";
}
它的操作基于这样一个事实,即流已经使用区域设置来判断字符是否为空白,并使用该区域设置来决定在字符串中读取什么。因此,在这里我们利用了这一点,只需稍微修改一下,就可以将新行归类为非空白,这样它们就可以保留在输出中。除此之外,流已经做了我们想要的事情,知道如何忽略连续运行的空白,所以我们只是利用它,而不是复制它