2017-05-04 67 views
0
[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)的文本文件复制到焦炭的载体,附加字符“\ n”。
2)循环遍历所有'\ n',直到它连续发现它们中的2个。
3)一旦确定,它会在接下来的9个字符处查看(时间戳不包括最后一个字符']'),并将其存储到一个变量中。
4)删除不必要的字符'['和':',取前2个数字,乘以60(使秒),并将其添加到接下来的2个数字并存储到一个int。
5)将int减去0.8,并将秒转换为分钟,将其转换为字符,然后重新添加字符'['和':'。
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 =“\ n! \ n')没有工作。如何检查* i是否等于2个换行符?
2)你如何“偷看”新的几个字符,而无需迭代并将其存储到变量中?
3)如何在迭代过程中将新计算的时间戳添加到矢量的中间?

预先感谢您。

+0

你为什么不计算时间戳?如果遇到空行,请设置一个标志,然后在读取下一个非空行时,首先按调整后的空时间戳,重置标志并继续。当你有多个连续的空行时,你不知道你想要做什么。如果时间戳由空行分隔的时间间隔小于800毫秒,您也不清楚要执行什么操作。你保证时间戳总是小于99:59.99吗? – paddy

+0

我会先回答你的后面的问题。不会有任何连续的空行,保证。如果由空行分隔的时间戳间隔小于800毫秒,那么如果空行具有2个时间戳的平均值,我希望它。是的,时间戳将保证小于99:59.99。至于你的第一个问题,我不完全确定如何完成。 – user3245228

+0

*“将int减去0.8”*您不会满意从整数减去0.8的结果。更好地将你的整个时间戳翻译成一个整数(m * 6000 + s * 100 +分数)并减去80. – grek40

回答

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个问题,我想这可以在一个单独的答案中解决。但是你的问题来自一个混乱的方法,并且需要混乱的解决方案。也许你只是不想去那里。

+0

为了好奇,我非常感兴趣的是如何运作。如果你有时间,我很乐意阅读你的推理和你的答案。但是,您给我的解决方案很多,因此我会将其标记为解决方案。非常感谢你。 – user3245228

+0

解决方案的哪些部分需要帮助理解? – paddy

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::duration为所需精度:centiseconds

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

  3. 当输入文件是好的:

    A.尝试解析时间戳。

    B.如果解析失败,并且我们没有命中文件结尾,则使用空行。 C.解析空白行后面的时间戳。

    D.计算插值时间戳并将其格式化。 E.解析当前时间戳的可选行号,然后将所有内容格式化。 F.记住下一次迭代的时间戳记,以便可以根据需要做出平均值。

这种配方不需要vector整个输入文件存储在通过线只需输出,当您去,行。

你不能简单的使用strptime/strftime/get_time/put_time的解析和格式化,因为他们不处理亚秒级的精度。

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

相关问题