C++中读取格式化输入最简单的方法是什么?

21

有没有办法读取这样格式化的字符串,比如说::48754+7812=Abcs

假设我有三个字符串 X、Y 和 Z,我想

X = 48754 
Y = 7812
Z = Abcs

这两个数字的大小和字符串的长度可能会有所不同,因此我不想使用substring()或类似的函数。

是否可能在C++中传递这样的参数?

":#####..+####..=SSS.."

所以它直接知道发生了什么?

4个回答

30
#include <iostream>
#include <sstream>

int main(int argc, char **argv) {
  std::string str = ":12341+414112=absca";
  std::stringstream ss(str);
  int v1, v2; 
  char col, op, eq; 
  std::string var;
  ss >> col >> v1 >> op >> v2 >> eq >> var;
  std::cout << v1 << " " << v2 << " " << var << std::endl;
  return 0;
}

9
+1 是因为这是唯一一个精确考虑了实际问题的答案。其他答案没有,因为1. 使用 boost 不是最简单的方法(我承认这可能是最优雅的方法),2. scanf 不符合 C ++ 风格(正如相应答案的作者所提到的)。 - ChristophK

15

一个可能的解决方案是使用boost::split()函数,它允许指定多个分隔符,并且不需要预先知道输入的大小:

#include <iostream>
#include <vector>
#include <string>

#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/split.hpp>

int main()
{
    std::vector<std::string> tokens;
    std::string s(":48754+7812=Abcs");
    boost::split(tokens, s, boost::is_any_of(":+="));

    // "48754" == tokens[0]
    // "7812"  == tokens[1]
    // "Abcs"  == tokens[2]

    return 0;
}

或者,使用sscanf()函数:

#include <iostream>
#include <cstdio>

int main()
{
    const char* s = ":48754+7812=Abcs";
    int X, Y;
    char Z[100];

    if (3 == std::sscanf(s, ":%d+%d=%99s", &X, &Y, Z))
    {
        std::cout << "X=" << X << "\n";
        std::cout << "Y=" << Y << "\n";
        std::cout << "Z=" << Z << "\n";
    }

    return 0;
}

然而,这里的限制是在解析输入之前必须决定字符串(Z)的最大长度。


非常感谢您的回答,但除了boost或任何外部库之外,还有其他可行的方法吗? 是否可能在标准C++或至少STL中完成? - Loers Antario

6
您可以使用scanf。虽然它不是过度C++风格的,但只需极少的代码即可完成任务。
char a[101], b[111], c[121];
sscanf(":48754+7812=Abcs", ":%100[^+]+%110[^=]=%120s", a, b, c);
string sa(a), sb(b), sc(c);
cout << sa << "-" << sb  << "-" << sc << endl;

这个想法是使用非常有限的正则表达式语法来指定读取的字符串所接受的字符。在这种情况下,第一个字符串被读取到加号,第二个字符串被读取到等号。


4
例如。
#include <boost/regex.hpp>
#include <iostream>

int main()
{
   boost::regex re("\":(\\d+)\\+(\\d+)=(.+)\"");
   std::string example = "\":48754+7812=Abcs\"";
   boost::smatch match;
   if (boost::regex_match(example, match, re))
   {
      std::cout << "f number: " << match[1] << " s number: " << match[2] << " string: " << match[3]
      << std::endl;
   }
   else
   {
      std::cout << "not match" << std::endl;
   }
}

第二种方式仅适用于字符串。

#include <string>
#include <iostream>

int main()
{
   std::string s = "\":48754+7812=Abcs\"";
   std::string::size_type idx = s.find(":");
   std::string::size_type end_first = s.find("+", idx + 1);
   std::string f_number = s.substr(idx + 1, end_first - (idx + 1));
   std::cout << f_number << std::endl;
   std::string::size_type end_second = s.find("=", end_first + 1);
   std::string s_number = s.substr(end_first + 1, end_second - (end_first + 1));
   std::cout << s_number << std::endl;
   std::string::size_type string_end = s.find("\"", end_second);
   std::string str = s.substr(end_second + 1, string_end - (end_second + 1));
   std::cout << str << std::endl;
}

1
正则表达式在许多情况下都是一个好的建议,+1。请注意,C++11中已经包含了正则表达式支持,因此不再需要使用Boost regex。 - jogojapan
1
@jogojapan 现在不行=( http://liveworkspace.org/code/b66dcfa19ce7620fb7b9e4c203c42f43 - ForEveR
1
@ForEveR 是的,我应该检查一下,但事实证明GCC的正则表达式支持还不够好,特别是捕获组不起作用。此外,正则表达式语法也有所不同。例如,在C++11中执行[\d]的标准方法是[[:digit:]]。无论如何,最后一句话,如果您使用Clang,对C ++ 11正则表达式的支持会更好。通过正确的语法调整,您的示例代码就可以在那里工作了。 - jogojapan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接