使用c ++检索一些文本列比python慢​​得多

时间:2015-04-21 20:13:33

标签: python c++ regex split

我想阅读一些大文件内容并检查一些列然后根据样本行的列值存储一些文件行:

7774777761 72288833         2015/03/20     23:59:37       26       26   38 
  99944524 09671017         2015/03/20     23:59:44       18        1    8

我用Python这样做了:

import sys
if __name__=="__main__":
    if (len(sys.argv)<4):
        sys.stderr.write('Usage: trk finame fout  column value \n ')
        sys.exit(1)
    finame=open(sys.argv[1],'r')
    result=open(sys.argv[2],'w')
    nos=open("nos.txt",'w')
    col=int(sys.argv[3])
    val=sys.argv[4]
    for l in finame:
        llist=l.split()
        try:
            if llist[col]==val:
                result.write(l)
        except:
            nos.write(l)
    result.close()
    nos.close()

然后尝试使用regexp在C ++中完成:

#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <regex>
using namespace std;

int main(int argc, char* argv[])
{
  ifstream fstr;
  ofstream ofstr;
  string istr,result;
  int col;
  string val;
  if(argc<5){
    cout<<"you must enter right arguments"<<endl;
    cout<<"colgrab inputfile outputfile desired_col desired_val"<<endl;
    cout<<"for example :"<<endl;
    cout<<"colgrab TrkTicket.txt INCOM_HWI.txt 6 1"<<endl;
  }else{
    fstr.open(argv[1]);
    ofstr.open(argv[2]);
    col=atoi(argv[3]);
    val=argv[4];
    if(!fstr)
    {
      cerr << "File could not be opened" << endl;
      exit( 1 );
    }

    if(!ofstr)
    {
      cerr << "File could not be opened" << endl;
      exit( 1 );
    }
  }

  while(getline(fstr,istr)){
    //  cout<<istr<<endl;
    try {
      regex re(R"XXX( *(\d+) +(\d+) +(\d+/\d+/\d+) +(\d+:\d+:\d+) +(\d+) +(\d+) +(\d+).)XXX");
      std::smatch match;
      //cout<<istr<<endl;
      if (regex_search(istr, match, re) && match.size() > 1) {
        result = match.str(col);

        if(val==result){
          ofstr<<istr<<endl;
        }
        //cout<<result<<endl;
      } else {
        //result = std::string("No match found");
        //cout<<result<<endl;

      }
    } catch (std::regex_error& e) {
      // Syntax error in the regular expression
      //cerr<<"Syntax error in the regular expression "<<endl;
    }
  }


  return 0;
}

我这样做的目的是速度。但让我感到惊讶的是,Python版本在不到10秒内完成了270 Mb文件的工作,但C ++版本无法在10分钟内完成工作。

如何修复c ++版本以便在更短的时间内完成工作?


Python版python 3.2

C ++版本GCC G ++ 4.9.1


修改1

我尝试了所有提议的方法,并且使用MikeMB的方式它们几乎是均匀的:

&#13;
&#13;
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <regex>
using namespace std;

int main(int argc, char* argv[])
{
    ifstream fstr;
    ofstream ofstr;
    string istr,result;
    int col;
    string val;
    if(argc<5){
        cout<<"you must enter right arguments"<<endl;
        cout<<"colgrab inputfile outputfile desired_col desired_val"<<endl;
        cout<<"for example :"<<endl;
        cout<<"colgrab TrkTicket.txt INCOM_HWI.txt 6 1"<<endl;
    }else{
    fstr.open(argv[1]);
    ofstr.open(argv[2]);
    col=atoi(argv[3]);
    val=argv[4];
    if(!fstr)
       {
          cerr << "File could not be opened" << endl;
          exit( 1 );
       }

    if(!ofstr)
       {
          cerr << "File could not be opened" << endl;
          exit( 1 );
       }
    }

while(getline(fstr,istr)){
        stringstream sstr(istr);
        int i = 0;
        while (sstr >> result) {
           if (i == col-1 && result == val) {
               ofstr << istr << "\n";
               break;
           }
           i++;
        }
 


    return 0;
}
&#13;
&#13;
&#13;

有没有办法提高性能?

3 个答案:

答案 0 :(得分:1)

编辑1 的答案:

  • 添加std::ios::sync_with_stdio(false);作为main()的第一行 很好的速度提升。

  • 您不需要阅读一行,然后将其转换为stringstream - 您可以直接从fstr读取值以避免复制。

  • 要以毫秒为单位获取数据,您可以使用索引数据格式,例如将数据导入SQLite database,索引列并使用数据库查询来提取数据。

答案 1 :(得分:0)

为了完全删除regex,您可以尝试此操作(仅修改while循环):

while(getline(fstr,istr)){
    stringstream sstr(istr);
    string field[7];
    for(int i = 0; i < 7; i++)
        sstr >> field[i];

    // do whatever you want with read values
}

假设您读取的每行有7列且列中的值不包含空格,则应该可以正常工作。

答案 2 :(得分:0)

构建正则表达式非常昂贵,因为它涉及构建状态机,因此,如评论中所述,您应该将正则表达式构造移出循环,因此您只需支付该价格一次。

然而,对于这么简单的案例,你可能根本不需要正则表达式。我不确定这实际上是否更快,但您可以尝试以下方法:

while (getline(fstr, istr)){        
    std::stringstream ss(istr);
    int i = 0;      
    while (ss >> result) {              
        if (i == col && result == val) {
            ofstr << istr << "\n";
            break;
        }
        i++;
    }
}