根据类型标记字符串流
Tokenize stringstream based on type
我有一个包含整数和特殊含义字符'#'的输入流。它看起来如下: ... 12 18 16 # 22 24 26 15 # 17 # 32 35 33 ...
令牌用空格分隔。"#"的位置没有模式。
我试图像这样标记输入流:
int value;
std::ifstream input("data");
if (input.good()) {
string line;
while(getline(data, line) != EOF) {
if (!line.empty()) {
sstream ss(line);
while (ss >> value) {
//process value ...
}
}
}
}
此代码的问题在于,当遇到第一个"#"时,处理将停止。
我能想到的唯一解决方案是将每个单独的令牌提取到一个字符串(不是"#")并使用 atoi() 函数将字符串转换为整数。但是,由于大多数令牌是整数,因此效率非常低。在令牌上调用 atoi() 会带来很大的开销。
有没有办法按类型解析单个令牌? 即,对于整数,将其解析为整数,而对于"#",跳过它。谢谢!
一种可能性是显式跳过空格(ss >> std::ws
),然后使用ss.peek()
来确定是否遵循#
。如果是,请使用 ss.get()
读取它并继续,否则使用 ss >> value
读取该值。
如果#
的位置无关紧要,您还可以在使用它初始化stringstream
之前从行中删除所有'#'
。
通常不值得针对 good() 进行测试
if (input.good()) {
除非下一个操作生成错误消息或异常。如果不好,所有进一步的操作都将失败。
不要针对EOF
进行测试。
while(getline(data, line) != EOF) {
std::getline() 的结果不是整数。它是对输入流的引用。输入流可转换为类似布尔值的对象,该对象可以在布尔上下文(如while
if
等)中使用。所以你想做什么:
while(getline(data, line)) {
我不确定我会读一行。你可以只读一个单词(因为输入是空格分隔的)。对字符串使用>> 运算符
std::string word;
while(data >> word) { // reads one space separated word
现在你可以测试这个词,看看它是否是你的特殊字符:
if (word[0] == "#")
如果没有,则将单词转换为数字。
这就是我要做的:
// define a class that will read either value from a stream
class MyValue
{
public:
bool isSpec() const {return isSpecial;}
int value() const {return intValue;}
friend std::istream& operator>>(std::istream& stream, MyValue& data)
{
std::string item;
stream >> item;
if (item[0] == '#') {
data.isSpecial = true;
} else
{ data.isSpecial = false;
data.intValue = atoi(&item[0]);
}
return stream;
}
private:
bool isSpecial;
int intValue;
};
// Now your loop becomes:
MyValue val;
while(file >> val)
{
if (val.isSpec()) { /* Special processing */ }
else { /* We have an integer */ }
}
也许您可以将所有值读取为 std::string,然后检查它是否为"#"(如果不是 - 转换为 int)
int value;
std::ifstream input("data");
if (input.good()) {
string line;
std::sstream ss(std::stringstream::in | std::stringstream::out);
std::sstream ss2(std::stringstream::in | std::stringstream::out);
while(getline(data, line, '#') {
ss << line;
while(getline(ss, line, ' ') {
ss2 << line;
ss2 >> value
//process values ...
ss2.str("");
}
ss.str("");
}
}
在这里,我们首先在第一个 while 循环中用标记"#"拆分行,然后在第二个 while 循环中,我们将行拆分为"。
就个人而言,如果您的分隔符无论以下内容如何都始终是空格,我建议您仅将输入作为字符串并从那里解析。这样,你可以获取字符串,看看它是一个数字还是一个#等等。
你应该重新检查你的前提,即"在令牌上调用atoi()会带来很大的开销-"
没有魔法可以std::cin >> val
.在引擎盖下,它最终调用(非常类似于)atoi。
如果你的代币很大,创建一个std::string
可能会有一些开销,但正如你所说,绝大多数是数字(其余的是#),所以它们应该大多很短。
- 如何检查模板类中的变量是否为字符串类型?
- C++类字符串类型的迭代器
- 如何将字符串指针数组转换为字符串类型的智能指针向量?
- 字符串类型的 2d 数组(C++;)
- 在 Rcpp 中的字符串类型之间转换时出错
- 为什么字符串类型会导致 c++ 程序无法运行?
- 如何将字符串类型转换为 ostringstream
- 当正斜杠运算符应用于C++中的字符串类型时,它会做什么
- 添加字符串类型的类成员会导致调用基类函数而不是子函数
- 我在 c++ 中声明字符串类型时遇到问题
- 对齐C++字符串类型问题 std::字符串到 TStr
- C++无符号字符串类型的正则表达式
- 当 JSON 值应为 INT 但以字符串类型发送时,RapidJSON 崩溃
- 如何使用 std::find 从向量的第一个元素中查找字符串<字符串对<字符串、字符串> >类型?
- 我想添加两个字符串类型的矩阵.用户将不会输入行数或列的数量.用户将仅输入数组
- 为什么数组(字符串类型)的大小是 24 字节,带有单个空格元素
- 如何根据定义的字符串类型在“std::cout”和“std::wcout”之间进行选择
- C++ 仅当模板为字符串类型时执行小写转换
- 字符串类型的 C++ 模板无法编译
- 如何使用新字符串而不是分配器创建自己的字符串类型向量?