逐步阅读文本文件

Read text file step-by-step

本文关键字:文本 文件      更新时间:2023-10-16

我有一个文件,文本如下:

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

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

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

我第一次尝试用Python做,但是文件真的很大,处理文件需要很长时间,所以我决定用c++写这部分。然而,我对c++正则表达式一无所知,我正在寻求帮助。你可以,请,推荐给我一个简单的正则表达式库(我不太了解c++)或良好的文档?如果您提供一个小示例(我知道如何使用fstream执行文件传输,但我需要帮助如何读取文件,正如我之前所说的),那就更好了。

这看起来是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";
}

IMO, c++不是你任务的最佳选择。但如果你必须在c++中做,我建议你看看Boost。Regex, Boost库的一部分。

如果是Unix,一个简单的sed 's/#/ /' <infile >outfile就足够了。

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

好吧,我要把这变成一个答案而不是注释。不要使用正则表达式。对于这项任务来说,这几乎肯定是多余的。我对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++方法中的任何一种来做,也不是说这些方法都是理想的——我只是在这里指出有很多很多方法来解析字符串。Regex非常强大,甚至可以在极端情况下拯救世界,但它不是解析文本的唯一方法,如果用于错误的事情,甚至可能会毁灭世界。真的。

如果你坚持使用正则表达式(或被迫使用,如在家庭作业中),那么我建议你听克里斯的,使用Boost.Regex。另外,如果您想尝试其他东西,我知道Boost也有一个很好的字符串库。如果使用正则表达式,请注意克苏鲁。

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

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

如果你想让每个#变成一个空格,那么可能最简单的方法就是编写c风格的代码:

#include <stdio.h>
int main() { 
    int ch;
    while (EOF!=(ch=getchar()))
        if (ch == '#')
            putchar(' ');
        else
            putchar(ch);
    return 0;
}

所以,您想用一个字符' '替换每个字符'#',对吗?

那么这很容易做到,因为你可以用完全相同长度的字符串替换文件的任何部分,而不会干扰文件的组织。
重复这样的替换允许逐个块地对文件进行转换;因此,您可以避免读取内存中的所有文件,当文件非常大时,这是有问题的。

以下是Python 2.7中的代码:

也许,块块替换将不足以使其更快,并且您将很难在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'以精确控制文件指针的位置和移动;
mode '+'是能够读写文件

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个文件的指针