逐步阅读文本文件

时间:2011-10-05 17:39:54

标签: c++ regex file-io

我的文件有这样的文字:

#1#14#ADEADE#CAH0F#0#0.....

我需要创建一个代码,找到#符号后面的文本,将其存储到变量中,然后将其写入文件WITHOUT#符号,但之前有空格。所以从以前的代码我会得到:

1 14 ADEADE CAH0F 0 0......

我首先尝试在Python中完成它,但文件非常大,处理文件需要非常大的时间,所以我决定用C ++编写这个部分。但是,我对C ++正则表达式一无所知,我正在寻求帮助。请问,请您推荐一个简单的正则表达式库(我不太了解C ++)或者记录良好的库?如果你提供一个小例子(我知道如何使用fstream执行传输到文件,但我需要如何阅读文件,如前所述),那就更好了。

6 个答案:

答案 0 :(得分:4)

这看起来像是std::locale的工作和他值得信赖的伙伴imbue

#include <locale>
#include <iostream>


struct hash_is_space : std::ctype<char> {
  hash_is_space() : std::ctype<char>(get_table()) {}
  static mask const* get_table()
  {
    static mask rc[table_size];
    rc['#'] = std::ctype_base::space;
    return &rc[0];
  }
};

int main() {
  using std::string;
  using std::cin;
  using std::locale;

  cin.imbue(locale(cin.getloc(), new hash_is_space));

  string word;
  while(cin >> word) {
    std::cout << word << " ";
  }
  std::cout << "\n";
}

答案 1 :(得分:1)

IMO,C ++不是您任务的最佳选择。但如果你必须用C ++做,我建议你看看Boost.Regex,它是Boost库的一部分。

答案 2 :(得分:1)

如果您使用的是Unix,那么简单的sed 's/#/ /' <infile >outfile就足够了。

Sed代表'流编辑器'(并支持正则表达式!whoo!),因此它非常适合您正在寻找的性能。

答案 3 :(得分:0)

好吧,我只想把它作为答案而不是评论。不要使用正则表达式。对于这项任务来说,这几乎肯定是过度的。我对C ++有点生疏,所以我不会发布任何丑陋的代码,但基本上你可以做的是一次解析一个字符,将任何不是#的东西放入缓冲区,然后在点击#时将其写入输出文件以及空格。在C#中,至少有两种解决这个问题的方法很简单:

StreamReader fileReader = new StreamReader(new FileStream("myFile.txt"),
                              FileMode.Open);
string fileContents = fileReader.ReadToEnd();
string outFileContents = fileContents.Replace("#", " ");
StreamWriter outFileWriter = new StreamWriter(new FileStream("outFile.txt"),
                                 Encoding.UTF8);
outFileWriter.Write(outFileContents);
outFileWriter.Flush();

或者,您可以替换

string outFileContents = fileContents.Replace("#", " ");

使用

StringBuilder outFileContents = new StringBuilder();
string[] parts = fileContents.Split("#");
foreach (string part in parts)
{
    outFileContents.Append(part);
    outFileContents.Append(" ");
}

我不是说你应该采用这些方法或我建议的C ++方法,也不是任何这些方法都是理想的 - 我只是在这里指出有很多方法来解析字符串。正则表达式非常强大,在极端情况下甚至可能save the day,但它不是解析文本的唯一方法,如果用于错误的事情,甚至可能destroy the world。真。

如果你坚持使用正则表达式(或被迫,如在家庭作业中),那么我建议你听Chris并使用Boost.Regex。或者,我知道如果您想尝试别的东西,Boost也有一个很好的字符串库。如果您使用正则表达式,请留意Cthulhu

答案 4 :(得分:0)

你遗漏了一个关键点:如果输入中有两个(或更多)连续的# s,它们应该变成一个空格,还是相同数量的空格有{{1} }} S'

如果你想把整个字符串变成一个空格,那么@ Rob的解决方案应该可以很好地工作。

如果你想让每个#变成一个空格,那么编写C风格的代码可能最容易:

#

答案 5 :(得分:0)

那么,你想用一个字符'#'替换每一个字符' ',对吗?

然后很容易做到,因为你可以用完全相同长度的字符串替换文件的任何部分而不会扰乱文件的组织。
重复这样的替换允许通过块来转换文件块;所以你要避免读取内存中的所有文件,这在文件非常大时会出现问题。

这是Python 2.7中的代码。

也许,chunk的替换块将使其更快,并且你将很难用C ++编写相同的块。但总的来说,当我提出这样的代码时,它已经令人满意地增加了执行的时间。

def treat_file(file_path, chunk_size):
    from os import fsync

    from os.path import getsize
    file_size = getsize(file_path)

    with open(file_path,'rb+') as g:
        fd = g.fileno() # file descriptor, it's an integer

        while True:
            x = g.read(chunk_size)
            g.seek(- len(x),1)
            g.write(x.replace('#',' '))
            g.flush()
            fsync(fd)
            if g.tell() == file_size:
                break

评论:

open(file_path,'rb+')

绝对必须以二进制模式'b'打开文件,以精确控制文件指针的位置和移动;
 模式'+'是能够在文件中读取和写入

fd = g.fileno()

文件描述符,它是一个整数

x = g.read(chunk_size)

读取大小 chunk_size 的块。给它读取缓冲区的大小是很棘手的,但我不知道如何找到这个缓冲区的大小。因此,一个好主意就是给它一个2值的力量。

g.seek(- len(x),1)

文件的指针被移回到刚刚读取块的位置。它必须是len(x),而不是 chunk_size ,因为最后一个块读取通常不会长于 chink_size

g.write(x.replace('#',' '))

使用修改后的块

写入相同的长度
g.flush()
fsync(fd)

这两条指令强制写入,否则修改后的块可能会保留在写入缓冲区中并在不受控制的时刻写入

if g.tell() >= file_size:  break

在读取文件的最后一部分后,无论其长度是什么(小于或等于chunk_size),文件的指针都位于文件的最大位置,即 file_size 和该计划必须停止

如果你想用一个连续替换几个'### ...',代码很容易修改以满足这个要求,因为写一个缩短的块不会擦除仍未读取的字符。文件。它只需要2个文件的指针。