在C ++中从文件中获取输入时如何跳过阅读“:”

时间:2018-11-25 20:45:05

标签: c++ file

让我们说我想从文件的第一行输入小时,分钟和秒,并将它们分别存储到3个不同的变量中,分别是小时,分钟和秒。 我想不通一种简单的方法来跳过阅读冒号(“:”)。

输入文件示例:

12:49:00

商店:

hrs = 12
mins = 59
sec = 00

4 个答案:

答案 0 :(得分:3)

您可以一次使用std::regex来进行匹配,范围检查和验证输入。

#include <iostream>
#include <regex>
#include <string>

int main()
{
    const std::regex time_regex("(\\d|[0,1]\\d|2[0-3]):([0-5]\\d):([0-5]\\d)");
    std::smatch time_match;
    std::string line;

    while (std::getline(std::cin, line))
    {
        if (std::regex_match(line, time_match, time_regex))
        {
            int hours = std::stoi(time_match[1]);
            int minutes = std::stoi(time_match[2]);
            int seconds = std::stoi(time_match[3]);
            std::cout << "h=" << hours << " m=" << minutes << " s=" << seconds << std::endl;
        }
        else
        {
            std::cout << "Invalid time: " << line << std::endl;
        }
    }

    return 0;
}

实时观看此示例here

打破正则表达式(\\d|[0,1]\\d|2[0-3]):([0-5]\\d):([0-5]\\d)

  1. \d|[0,1]\d|2[0-3]匹配以下时间之一的小时(24小时制):

    • \d:0-9
    • [0,1]\d:01-19
    • 2[0-3]:20-23
  2. [0-5]\d匹配分钟:两位数字00-59

  3. [0-5]\d与秒匹配:两位数字00-59,如上所述。

答案 1 :(得分:2)

不使用临时字符跳过冒号的替代方法:

#include <iostream>
int main()
{
        int h,m,s;
        std::cin >> h;
        std::cin.ignore(1) >> m;
        std::cin.ignore(1) >> s;
        std::cout << h << ':' << m << ':' << s << std::endl;
        return 0;
}

答案 2 :(得分:1)

这似乎可行:

int h, m, s;                                                                                                                                                                                                                               
char c;                                                                                                                                                                                                                                    
cin >> h >> c >> m >> c >> s;

您只需以这种方式跳过:符号。我不知道这是不是一个好的解决方案。

使用cin.ignore

cin >> h;                                                                                                                                                                                                                                  
cin.ignore(1);                                                                                                                                                                                                                             
cin >> m;                                                                                                                                                                                                                                  
cin.ignore(1);                                                                                                                                                                                                                             
cin >> s;

答案 3 :(得分:0)

已经有好几个答案,一个已经被接受;但是,我想提出我的解决方案,不仅是对您的问题的有效答案,而且还是关于良好设计实践的建议。恕我直言,当它涉及从文件中读取信息并将其内容存储到变量或数据结构中时,我更喜欢以特定方式进行操作。我喜欢将特定操作的功能和职责分为各自的功能:


  
      
  • 1:我首先喜欢具有一个打开文件,读取内容并将信息存储到字符串,流或大缓冲区中的功能。一旦从文件中读取了适当数量的信息,该函数将在处理完文件后关闭文件句柄,然后返回结果。有几种方法可以做到这一点,但它们都是相似的。      
        
    • a :从文件中读取一行,然后返回字符串或流。
    •   
    • b:逐行读取文件中的所有信息,并将每行存储到其自己的字符串或流中,并返回这些字符串或流的向量。
    •   
    • c:将文件的所有内容读入单个字符串,流或大缓冲区,然后将其返回。
    •   
  •   
  • 2 :在我拥有该文件的内容之后,通常将调用一个函数,该函数将解析该数据,并且这些函数将根据需要根据解析的内容类型而有所不同。将要使用的数据结构。同样,这些解析函数将调用一个函数,该函数会将字符串拆分为称为标记的字符串向量。调用分割字符串函数后,数据解析将使用字符串操纵器-转换器将字符串转换为正在使用的当前数据结构所需的内置类型,并将其存储到通过引用传递。
  •   
  • 3::splitString函数有两个变体。      
        
    • a:一个以单个字符作为分隔符。
    •   
    • b:另一个将字符串作为分隔符。
    •   
    • c:这两个函数将根据使用的分隔符返回一个字符串向量。
    •   
  •   

这是我使用此文本文件进行输入的代码示例。

time.txt

4:32:52

main.cpp

#include <vector>
#include <string>
#include <sstream>
#include <fstream>
#include <iostream>
#include <exception>

struct Time {
    int hours;
    int minutes;
    int seconds;
};

std::vector<std::string> splitString( const std::string& s, char delimiter ) {
    std::vector<std::string> tokens;
    std::string token;
    std::istringstream tokenStream( s );
    while( std::getline( tokenStream, token, delimiter ) ) {
        tokens.push_back( token );
    }

    return tokens;
}

std::string getLineFromFile( const char* filename ) {
    std::ifstream file( filename );
    if( !file ) {
        std::stringstream stream;
        stream << "failed to open file " << filename << '\n';
        throw std::runtime_error( stream.str() );
    }

    std::string line;
    std::getline( file, line );

    file.close();

    return line;
}

void parseLine( const std::string& fileContents, Time& time ) {
    std::vector<std::string> output = splitString( fileContents, ':' );

    // This is where you would want to do your sanity check to make sure
    // that the contents from the file are valid inputs before converting
    // them to the appropriate types and storing them into your data structure.

    time.hours = std::stoi( output.at( 0 ) );
    time.minutes = std::stoi( output.at( 1 ) );
    time.seconds = std::stoi( output.at( 2 ) );
}

int main() {
    try {
        Time t;
        std::string line = getLineFromFile( "time.txt" );
        parseLine( line, t );

        std::cout << "Hours: " << t.hours << '\n'
            << "Minutes: " << t.minutes << '\n'
            << "Seconds: " << t.seconds << "\n\n";

    } catch( std::runtime_error& e ) {
        std::cerr << e.what() << std::endl;
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}

输出:

Hours: 4
Minutes: 32
Seconds: 52

现在,您可以在这种特殊情况下看到此处使用的功能仅设计用于从文件中读取一行,当然也从文件中读取第一行。我的库中还有其他未在此处显示的功能,这些功能将读取文件的每一行,直到没有更多的行可供读取,或将所有文件读取到单个缓冲区中为止。我有另一个版本的拆分字符串,它将字符串作为分隔符,而不是单个字符。最后,对于解析函数,由于每个解析函数都依赖于您要使用的数据结构,因此最终将是唯一的。

这使代码易于读取,因为每个函数都执行了应做的事情,仅此而已。我更喜欢这种设计,而不是试图从文件中获取信息并尝试在文件打开时解析它。打开文件时,如果发生错误或损坏的数据,但是编译器没有抱怨的地方,太多的事情可能出错,那么您的变量或数据结构可能包含无效信息,而您却没有意识到。至少以这种方式,您可以打开文件,从文件中获取所需内容,然后将其存储到字符串或字符串向量中,完成读取后关闭文件,然后返回内容。然后,标记数据后,解析功能将负责测试数据。现在,在上面显示的当前解析函数中,我没有进行任何健全性检查来使事情保持简单,但这是您在返回填充的数据结构之前测试数据以查看信息是否有效的地方。


如果您对从文件中读取多行的该版本的另一个版本感兴趣,只需注释一个请求,然后我会将其附加到此答案中。