在C++中的格式化输入。像这样---> x:y:z

4
我想在C++语言中以这种格式(x : y:z)输入数据。 在输入部分,输入的格式应该是这样的:
x : y : z
其中,x、y和z是三个独立的整数类型输入。
2个回答

4
您可以像这样从任何流中读取它。
#include <iostream>

int main() {

    int x, y, z;
    char colon;

    if (std::cin >> x >> colon >> y >> colon >> z) {

        std::cout << "\nYou entered:\t" << x << "\t" << y << "\t" << z;
    }
    else {
        std::cerr << "\nError: Wrong input format\n";
    }
    return 0;
}

编辑:根据Alan Birtles的评论,我将添加输入验证。尽管在问题中我无法读取到这些信息。
在人们想要概括这个问题之前,我会先回答这个问题。
但首先,您也可以使用:
 if ((std::cin >> x >> colon) && (colon ==':') && (std::cin >> y >> colon) && (colon == ':') && (std::cin >> z)) {

虽然我认为没有人关心这个,但是为了完整起见...


对于一般情况。最好使用std::getline来读取一行完整的输入,然后再进行分割。

这种任务永远不需要boost库。

以下是一些常见的字符串拆分模式:

将字符串拆分成标记是一项非常古老的任务。有许多解决方案可用。它们具有不同的属性。有些难以理解,有些难以开发,有些更复杂,速度可能更慢或更快、更灵活或不灵活。

其他选择

  1. 手工制作,有许多变体,使用指针或迭代器,可能难以开发并容易出错。
  2. 使用旧式的std::strtok函数。可能不安全。也许不再应该使用。
  3. std::getline。最常用的实现。但实际上是一种“滥用”,不太灵活。
  4. 使用专门为此目的开发的现代函数,最灵活,很适合STL环境和算法景观。但速度较慢。

请参见一段代码中的4个示例。

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <regex>
#include <algorithm>
#include <iterator>
#include <cstring>
#include <forward_list>
#include <deque>

using Container = std::vector<std::string>;
std::regex delimiter{ "," };


int main() {

    // Some function to print the contents of an STL container
    auto print = [](const auto& container) -> void { std::copy(container.begin(), container.end(),
        std::ostream_iterator<std::decay<decltype(*container.begin())>::type>(std::cout, " ")); std::cout << '\n'; };

    // Example 1:   Handcrafted -------------------------------------------------------------------------
    {
        // Our string that we want to split
        std::string stringToSplit{ "aaa,bbb,ccc,ddd" };
        Container c{};

        // Search for comma, then take the part and add to the result
        for (size_t i{ 0U }, startpos{ 0U }; i <= stringToSplit.size(); ++i) {

            // So, if there is a comma or the end of the string
            if ((stringToSplit[i] == ',') || (i == (stringToSplit.size()))) {

                // Copy substring
                c.push_back(stringToSplit.substr(startpos, i - startpos));
                startpos = i + 1;
            }
        }
        print(c);
    }

    // Example 2:   Using very old strtok function ----------------------------------------------------------
    {
        // Our string that we want to split
        std::string stringToSplit{ "aaa,bbb,ccc,ddd" };
        Container c{};

        // Split string into parts in a simple for loop
#pragma warning(suppress : 4996)
        for (char* token = std::strtok(const_cast<char*>(stringToSplit.data()), ","); token != nullptr; token = std::strtok(nullptr, ",")) {
            c.push_back(token);
        }

        print(c);
    }

    // Example 3:   Very often used std::getline with additional istringstream ------------------------------------------------
    {
        // Our string that we want to split
        std::string stringToSplit{ "aaa,bbb,ccc,ddd" };
        Container c{};

        // Put string in an std::istringstream
        std::istringstream iss{ stringToSplit };

        // Extract string parts in simple for loop
        for (std::string part{}; std::getline(iss, part, ','); c.push_back(part))
            ;

        print(c);
    }

    // Example 4:   Most flexible iterator solution  ------------------------------------------------

    {
        // Our string that we want to split
        std::string stringToSplit{ "aaa,bbb,ccc,ddd" };


        Container c(std::sregex_token_iterator(stringToSplit.begin(), stringToSplit.end(), delimiter, -1), {});
        //
        // Everything done already with range constructor. No additional code needed.
        //

        print(c);


        // Works also with other containers in the same way
        std::forward_list<std::string> c2(std::sregex_token_iterator(stringToSplit.begin(), stringToSplit.end(), delimiter, -1), {});

        print(c2);

        // And works with algorithms
        std::deque<std::string> c3{};
        std::copy(std::sregex_token_iterator(stringToSplit.begin(), stringToSplit.end(), delimiter, -1), {}, std::back_inserter(c3));

        print(c3);
    }
    return 0;
}

请注意,此代码将接受任何字符分隔符,甚至不使用分隔符,在后一种情况下,它将吸收数字的第一个字符。 - Alan Birtles
@AlanBirtles:是的,你说得对。但请理解,首先谁会问这样的问题呢?我现在添加了很多代码。但那些代码并不适合OP当前的技能水平。因此,最初的答案,就像它本来的样子,更好。 - A M
直到他们意外地输入错误并花费大量时间调试为什么输出不正确。输入验证很重要,应该在每个程序中,无论多么琐碎,以形成良好的习惯,不引入安全漏洞。 - Alan Birtles

0
一种可能性是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("x:y:z");
    boost::split(tokens, s, boost::is_any_of(":"));

    // "x"  == tokens[0]
    // "y"  == tokens[1]
    // "z"  == tokens[2]

    return 0;
}

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