将时间戳添加到文本文件中的空行

时间:2017-05-04 06:39:24

标签: c++ file timestamp

[00:00.00]
[00:54.25]1
[00:57.14]2
[01:01.04]3
[01:05.78]4
[01:08.03]5
[01:11.02]6
[01:14.21]7
[01:19.64]8

[01:21.83]9
[01:28.68]a
[01:33.34]b

[01:36.65]c
[01:40.58]d

考虑到文本文件中的以下文本,对于每个空白行,我想采用下一行的时间戳,将其减去0.8,并将其放在该空白行中。

[00:00.00]
[00:54.25]1
[00:57.14]2
[01:01.04]3
[01:05.78]4
[01:08.03]5
[01:11.02]6
[01:14.21]7
[01:19.64]8
[01:21.03]
[01:21.83]9
[01:28.68]a
[01:33.34]b
[01:35.85]
[01:36.65]c
[01:40.58]d  

这是我目前的思路:
1)将文本文件复制到char的向量中,附加char' \ n'在每一行的末尾。
2)循环通过所有' \ n'直到它连续发现其中的两个。
3)一旦完成,它会查看接下来的9个字符(排除最后一个字符的时间戳']'),并将其存储到变量中。
4)删除不必要的字符' ['并且':',取前两个数字,乘以60(使它们成为秒数),并将其添加到接下来的两个数字并将其存储到一个int中。
5)将int减去0.8并将秒转换为分钟,将其转换为char,然后重新添加字符' ['和':' 6)添加时间戳和字符']'两者之间' \ n' 7)循环到下一个' \ n'。

到目前为止,我只将文件推入向量并尝试查找2个新行:

using namespace std;

int main() {
    ifstream inFile("file.txt");
    vector<char> lineArray;
    string line;
    char newLine = '\n';
    ofstream outFile("newfile.txt");

    while (getline(inFile, line)) {
        copy(line.begin(), line.end(), back_inserter(lineArray));
        lineArray.push_back(newLine);
    }
    for (std::vector<char>::const_iterator i = lineArray.begin(); i != lineArray.end(); ++i) 
        if (*i != '\n\n') {
            std::cout << *i;
        }

    system("pause");
}

以下是我的以下问题:
1)如果(* i!=&#39; \ n \ n&#39;)没有奏效。如何检查* i是否等于2个换行符?
2)你如何偷看&#34;在新的几个字符没有迭代并将其存储到变量中? 3)如何在向量中间添加新计算的时间戳,同时进行迭代?

提前谢谢。

2 个答案:

答案 0 :(得分:0)

你的方法还可以,但你可能想得太辛苦了。而不是阅读所有数据然后再尝试处理它,而不是在你去的时候更容易处理它。

要阅读时间戳,请不要担心展望未来。只需使用std::regex分离当前行上的部分,然后转换为整数(允许您决定是否需要插值或偏移)。

任何与时间戳模式不匹配的非空行都可以被视为错误,但可以认为不匹配的模式实际上是空行。所以我的例子会完全忽略任何无效的行。

#include <iomanip>
#include <iostream>
#include <regex>
#include <string>
#include <vector>

int main()
{
    const std::regex timestamp_regex( "^\\[(\\d+):([0-5]\\d).(\\d\\d)\\]");
    std::smatch match;
    std::string line;
    std::vector<std::string> lines;
    int last_timestamp = 0;
    bool empty_line = false;

    while( std::getline( std::cin, line ) )
    {
        // Consider non-matching regex to be empty line, instead of line.empty()
        if( std::regex_search( line, match, timestamp_regex ) )
        {
            int timestamp = std::stoi( match[1] ) * 6000
                + std::stoi( match[2] ) * 100 
                + std::stoi( match[3] );

            // Offset or interpolate timestamp for single empty line
            if( empty_line )
            {
                empty_line = false;
                int t = timestamp - 80;
                if( t < last_timestamp ) t = (last_timestamp + timestamp) / 2;
                std::ostringstream oss;
                oss << std::setfill('0') << '['
                    << std::setw(2) << (t/6000) << ':'
                    << std::setw(2) << (t/100%60) << '.'
                    << std::setw(2) << (t % 100) << ']';
                lines.emplace_back( oss.str() );
            }
            last_timestamp = timestamp;
            lines.push_back( line );
        }
        else
        {
            empty_line = true;
        }
    }

    // Display all the lines
    for( auto & line : lines )
    {
        std::cout << line << std::endl;
    }
    return 0;
}

这是working example的链接 - 我应该指出编译器应该至少支持C ++ 11。

请注意,这些行都存储为字符串向量。但是如果你坚持使用单个连续的字节向量,那么这是一个微不足道的修改。

此外,如果您的时间戳不是按时间顺序排列,则会产生意外结果。

如果你真的想要回答你的3个问题,我想这可以在一个单独的答案中解决。但是你的问题来自凌乱的方法,需要凌乱的解决方案。也许你只是不想去那里。

答案 1 :(得分:0)

这是另一种方法,它使用Howard Hinnant's free, open source, header-only date library来解析和格式化时间戳,<chrono>用于时间戳计算。它需要C ++ 11,C ++ 14或C ++ 17,因为它基于<chrono>,直到C ++ 11才引入。它可以在Windows,gcc和clang(以及可能的其他)上移植。

#include "date.h"
#include <cassert>
#include <fstream>
#include <string>

int
main()
{
    using namespace std;
    ifstream inFile{"file.txt"};
    ofstream outFile{"newfile.txt"};
    string linenumber;
    istringstream in;
    using centiseconds = chrono::duration<int, centi>;
    centiseconds last_ts{0};
    constexpr centiseconds ts80{80};
    constexpr auto fmt = "[%M:%S]";
    while (inFile)
    {
        // Try to parse a time stamp
        centiseconds ts;
        inFile >> date::parse(fmt, ts);
        if (inFile.fail())
        {
            // Didn't work.  End of file?
            if (inFile.eof())
                break;
            // Ok, assume a blank line and consume it
            inFile.clear();
            inFile.ignore(1, '\n');
            // parse next line and assume it is a valid time stamp
            inFile >> date::parse(fmt, ts);
            assert(!inFile.fail());
            // Create and format the interpolated time stamp
            auto its = ts - last_ts < ts80 ? (ts + last_ts) / 2 : ts - ts80;
            outFile << date::format(fmt, its) << '\n';
        }
        getline(inFile, linenumber);  // parse optional line number
        // Format current time stamp, unchanged.
        outFile << date::format(fmt, ts) << linenumber << '\n';
        last_ts = ts;
    }
}
  1. 要做的第一件事就是为所需的精度创建自定义chrono::durationcentiseconds

  2. 接下来设置一些常量。 fmt = "[%M:%S]"字符串用于解析和格式化时间戳。

  3. 虽然输入文件很好:

    一个。尝试解析时间戳。

    B中。如果解析失败,并且我们没有命中文件结尾,请使用空白行。

    ℃。在空行后解析时间戳。

    d。计算插值时间戳并将其格式化。

    电子。解析当前时间戳的可选行号,然后将所有内容格式化。

    F。记住下一次迭代的时间戳,以便在需要时可以进行平均。

  4. 此公式不需要vector来存储整个输入文件。您只需逐行输出即可。

    您无法(轻松)使用strptime / strftime / get_time / put_time进行解析和格式化,因为它们不会处理亚秒级精度。

    请注意,缺少手动时间单位转换。这消除了常见的错误来源。