正则表达式是否足以分析大文本?

时间:2016-05-19 02:43:23

标签: c++ regex parsing

我有一个约1000000字的文本(只是一个例子),我想在一次迭代中解析它。而我想要做的是每次表达式匹配时,将其更改为其他内容。例如:

表达式:

| Expression     | New text |
|----------------|----------|
| ab             | A        |
| #{1,3}cb       | B        |
| [1234567890]db | C        |

文字:

  

Lorem ipsum dolor sit amet, ## cb consectetur adipiscing elit。结肠前膜韧带结构 #cb ,原始的laoreet ligula ultrices。在quis aliquam urna中,在 ab suscipit purus中。 Nunc posuere efficitur 9db nibh,tempor convallis mauris porta lobortis。

将输出文字:

  

Lorem ipsum dolor坐下来, B consectetur adipiscing elit。结肠前膜韧带 B ,原始的laoreet ligula ultrices。在quis aliquam urna中,在 A suscipit purus中。 Nunc posuere efficitur C nibh,tempor convallis mauris porta lobortis。

假设这些“常规”表达式不会相互重叠,有没有办法在c ++中使用std::regex实现这个?

我试过这样做,但有两个主要问题:

  • 它只匹配第一个和最后一个表达式。
  • 每个表达式只会迭代一次文本。

有没有办法解决这个问题,或者最好的解决方案是为这个特定目的编写解析器

3 个答案:

答案 0 :(得分:2)

正如EJP所说,即使你对解析器生成器一无所知,使用(f)lex也是微不足道的。 (你应该稍微看一下flex idiosyncratic regular expression syntax。就像每个面向正则表达式的工具一样,它有自己的怪癖。)

这是一个适合您任务的完整弹性计划:

file replacer.l

%option noinput nounput noyywrap
%%
ab         { fputs("A", stdout); }
"#"{1,3}cb { fputs("B", stdout); }
[0-9]db    { fputs("C", stdout); }

最后一行可能是[1234567890],但[0-9][[:digit:]]更为惯用。如倒数第二行所示,通过将特殊字符放在引号内引用特殊字符是很正常的,这是正则表达式工具所允许的。请注意,"abc"*是" abc"的任意数量的重复,与abc*完全不同。

最大的限制是没有捕获,虽然这似乎与您的问题无关,并且几乎总是有简单的解决方法。

编译并运行:

$ flex -o replacer.c replacer.l
$ gcc -o -Wall replacer replacer.c -lfl

$ ./replacer < lorem
Lorem ipsum dolor sit amet, Bconsectetur adipiscing elit. Vestibulum
posuere ligula in diam volutpat B, vitae laoreet ligula ultrices. In
quis aliquam urna, in A suscipit purus. Nunc posuere efficitur C nibh,
tempor convallis mauris porta lobortis.

我已经知道构建生成,编译和运行flex程序的快速而肮脏的工具,因为当输入文件很大时,结果可能比从标准实用程序中将事物拼凑在一起要快得多。例如,请参阅this answer on a companion site,它会向微型flex程序添加实际的main,以避免依赖-lfl

答案 1 :(得分:0)

我不知道如何使用std :: regex执行此操作,但您可以尝试使用boost :: iostreams :: regex_filter。来自their site的示例仅使用一个过滤器,但我相信您可以使用更多。例子:

#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/filter/regex.hpp>
#include <boost/regex.hpp>
#include <iostream>

using namespace boost::iostreams;

int main()
{
  char buffer[16];
  array_sink sink{buffer};
  filtering_ostream os;
  os.push(regex_filter{boost::regex{"Bo+st"}, "C++"});
  // push more filters here
  os.push(sink);
  os << "Boost" << std::flush;
  os.pop();
  std::cout.write(buffer, 3);
}

需要注意的是,根据文档,它会立即将所有文本读入内存。你的100万字应该不是问题,但对于千兆字节大小的文件,你可能遇到问题。

如果是我,我会手工替换,因为它可能不那么复杂。

答案 2 :(得分:0)

这是你可以做的。

设r1,r2,...,rn是你的正则表达式,r是它们的交替(r1)|(r2)| ... |(rn)。

  1. 找到r。
  2. 的第一次出现
  3. 分别与r1,r2,...,rn比较出现的情况。找到匹配项后,在第一次出现之前将所有内容写入目标文本,并替换。
  4. 重复其余文本。