我有一个我正在尝试解析的文本文件。该文件如下所示:
A_1: - A_10:
Some text.
----------
Some more text.
__________
B_1: - B_5:
Still more text - it may contain dashes as well.
----------
Even more text. Could be multiple sentences with newlines.
Like this.
__________
等等。
我正在尝试将bison
和flex
之间的解析/标记分开。我已设法使用A_1: - A_10:
中的以下正则表达式解析标题(flex
):
[ \t]+ ; // ignore whitespace
[A-Z]_[0-9]+(_[0-9]+)? { ... return ID; }
结合我的语法规则来组合两个ID:
header: ID ':' '-' ID ':'
但是,下一段文字会造成一些麻烦。我很确定我需要在词法分析器中包含启动条件(例如,在解析头时只忽略空格)。我试图定义一个令牌TEXT并解析整个事件直到----------
作为单个令牌。仍然无法弄清楚这是否合理。
我能想到的另一种可能性是在语法中有一个规则,它将使用WORD,SPACE,DASH,NEWLINE等标记和其他所有可能的字符组合文本段。它甚至有意义吗?
所以现在我不得不试图解析那些文本段。我是否使用合适的工具来完成工作。感谢您的帮助,谢谢。
答案 0 :(得分:3)
这是lex开始状态的目的。基本上,您为需要处理的每种不同语言声明一个开始状态(在您的情况下为两个 - 标题和正文),然后根据它们应用的状态标记规则。所以你想要的东西是:
%s header
%s body
%%
<header>[ \t\n] ; /* ignore */
<header>[_a-zA-Z][_a-zA-Z0-9]* { ... return ID; }
<header>[-:,.;()] { return *yytext; }
<body>^----------$ { yylval.text = GetStoredText(); return SECTION_SPLIT; }
<body>^__________$ { yylval.text = GetStoredText(); return SECTION_END; }
<body>. { StoreText(*yytext);
%%
void BeginHeader() { BEGIN header; }
void BeginBody() { BEGIN body; }
其中StoreText
是一个将字符存储到缓冲区的函数(如果你使用的是C ++,则类似于std :: stringstream),GetStoredText
返回自上次调用以来存储的所有文本并清除缓冲区。然后您的yacc / bison代码将类似于:
input: entry | input entry ;
entry: header body ;
header: ..something to match a header.. { BeginBody(); };
body: sections SECTION_END { BeginHeader(); };
sections: /*empty*/ | sections SECTION_SPLIT ;
当然,您还希望代码能够根据正文部分的内容做任何您想做的事情......
答案 1 :(得分:0)
我已经意识到逐行处理这样的文档(即编写适合该任务的自己的解析器)可能会产生更清晰的解决方案。
另一种可能性是在每个__________
标记处拆分整个文件。通过这种方式,我们将获得许多部分。然后将每个部分拆分为----------
个标记。现在我们能够提取当前部分的第二个文本块(“更多文本。”在上面的例子中的第一部分)。第一个文本块只是一行标题,后跟“Some text。”直到chunk结束。
这种算法很容易用Perl,Python,Ruby等脚本语言实现。