试图解析保存为std::字符串的大型文本文件

Trying to parse a large text file saved as an std::string

本文关键字:字符串 文本 文件 大型 std 保存      更新时间:2023-10-16

我有一个文本文件,我必须读入它,并从属于关键字的参数中提取数据。我正在读取的这个文本文件是要加载到其他文件中的查找表。我已经通过文件流将该文件读取到内存中,并将其保存为std::string。完整的文本文件现在作为私有成员变量std::string类型保存在我的类中。我正在调用类中的一个私有函数,该函数作为一个字符串传入此文本文件。此函数用于解析文件以查找关键字,然后从中提取数据。此外,一些关键词出现不止一次,我需要每次出现的次数。

这是我的txt文件的样子。

: This is a comment.
HEADER[AudioBookReader v1.0]
TITLE[Gulliver's Travel]
AUTHOR[Jonathan Swift]
YEAR[1726]
CHAPTER_COUNT[39]
TABLE_OF_CONTENTS
INTRO[intro]  
SECTION[Part I. A Voyage To Lilliput]
CHAPTER[gt_1_01] 
CHAPTER[gt_1_02]
: more CHAPTERs
SECTION[Part II. A Voyage To Brobdingnag]
CHAPTER[gt_2_01]
CHAPTER[gt_2_02]
: more CHAPTERs
SECTION[Part III. A Voyage To Laputa, Balnibarbi, Luggnagg, Glubbdubdrib, And Japan]
CHAPTER[gt_3_01]
CHAPTER[gt_3_02]
CHAPTER[gt_3_03]
: more CHAPTERs and SECTIONs

OUTRO[NONE]         : This is here as an example if there is none it can be 
: omitted or use the tag NONE inside the parameter braces. 
END                 : This tag represents the end of the file anything after
will not get parsed, as you can see I did not use a comment.

所有大写单词都是Tags或Keywords。大括号内的任何内容都是必需的数据。该行冒号":"之后的任何内容都将被跳过,END标记之后的任何东西都将被忽略,解析完成。大多数关键词都有相关的数据,在大多数情况下,我需要一系列文本。

只有前五个有数据的标签有一个实例。只有两个标签没有任何相关数据,即TABLE_OF_CONTENTSENDTABLE_OF_CONTENTS的唯一属性是表示我们已经到达了本书正文部分的开头。其余的标记可以显示多次。有些必须具有与其关联的数据,其他则是可选的。例如,INTRO是可选的Tags或Keywords。INTROOUTROCHAPTER的方括号内有文本—此文本表示没有扩展名的文件名。SECTIONNAME中的文本(如果显示的话)将只是保存到函数中的字符串中的文本,该函数正在解析存储在类内部结构中的文件。唯一可以存在于另一个关键字中的关键字是NONE。例如,NAME[NONE]将意味着没有与介绍、介绍或章节相关的名称。相反,最好完全省略NAME标记。但是,对于正在读取文本文件的用户来说,文本文件中的选项是制作自己的此类文件。

我的类几乎完成了,我所要做的就是创建这个解析函数,提取并保存我的数据。我对这个解析文件有一些规则要遵循。每个带有参数数据的关键字都位于文本文件中各自独立的行上。但是由于这个文件被读入并保存为字符串。以下是我的问题或担忧。

  1. 如何搜索这个存储的字符串,提取每个大括号之间的内容,并将其保存到子字符串中,同时统计每个关键字显示的次数。

  2. 与其一次将此文本文件的所有内容读入std::字符串,并让我的解析器逐行读取文本,直到文本结束,这是一个更好的解决方案吗?如果是,该如何做到?

Line-by-Line方法(我最初的方法)的问题有点困难,因为我在这个类之外有一个处理文本文件流的外部类。它是一个在文本中读取的继承类,其中我有另一个类,它是从与向文本写入文件的读取器相同的类中继承的。父类负责打开一个txt文件并保存带路径和不带路径的文本文件名,继承的类负责关闭父类打开的文件流。由于我的文本文件读取器只能一次读取所有数据并将其保存到字符串中,这就是为什么我将此文本文件作为字符串传递到我的解析函数中。

我还想保留这种文本文件格式的结构,并可能在未来将其作为二进制文件进行读取,同时拥有这两种选项。如果时间太长,我很抱歉,但有必要把我的观点讲清楚。它不仅仅是从中获取潜台词,还要跟踪重复的关键词,并确保某些关键词存在,而其他关键词是可选的。

由于未能将关注点分开,这让你自己很难过。

您遇到的主要问题只是解析。这是一项不平凡的任务。次要问题是std::string和处理文件I/O类。

解析是一项众所周知的任务。它可以很好地处理任何合理的文本表示,包括std::string。所以别再担心这些问题了。您的void parse(std::string wholeInput)方法应该只进行解析,而不执行其他操作。它根本不应该关心字符串的来源。

解析总是有语法的。有时它是用显式语法完成的,在这种情况下,有相当多的工具可以为您生成解析器。但是作为练习,您仍然可以编写自己的解析器。

解析的第一步是词法分析。这会将输入分解为单独的令牌。在这种情况下,您似乎有一些简单的词汇规则。标记是(1)可能带有下划线的字母序列,(2)[]或(3):和下一个换行符之间的任何字符。您甚至可以使用快捷方式,将注释视为空白,并在lexer中忽略它们。

解析的第二步现在得到了一组很好的预分类标记。这里可能需要两个函数,一个用于识别情况(1)中的关键字,另一个用于从情况(2)中的[ ]中获取参数。

第三步也是最后一步是用那些识别的关键字做一些特定于应用程序的事情。我不能给你太多建议,你应该知道如何处理这些关键词和它们的论点。但数起来当然很容易。