【问题标题】:Dart regex match against a streamDart 正则表达式匹配流
【发布时间】:2019-12-16 06:16:32
【问题描述】:

我正在编写代码来解析文本文件。 我的库的用户可以将行分隔符作为正则表达式传递。

文件可能很大,所以我需要流式传输内容。

所以问题是我如何在流通过我的行匹配器时将正则表达式应用于流。

我将应用一个限制,使正则表达式匹配的行分隔符不能超过 100 个字符,否则正则表达式有可能匹配文件的全部内容。

我不能只缓冲 100 个字符的最大值,因为分隔符可能跨越缓冲区。

我能想到的唯一想法是将正则表达式准备成段并检查部分匹配。

有更好的想法吗?

【问题讨论】:

    标签: regex dart stream


    【解决方案1】:

    这是一个棘手的问题,没有一个简单的解决方案。

    您的文件很大,因此您不想先将其完全加载到内存中。这是合理的。 您确实需要缓冲 一些 它,至少在最后检测到的行分隔符之后的所有内容,以便您可以将其与下一个块结合起来,以查找可能在块之间拆分的分隔符。

    这将是我最初的方法:保留一个“前缀”字符串,它是最后一行分隔符之后的所有内容,当您收到一个新块时,将其连接到前缀上,然后检查整个可用的行分隔符细绳。如果前缀(方式)超过 100 个字符,则可以将前缀拆分为绝对不属于分隔符的部分,然后将其直接放入 StringBuffer 中,最后 99 个字符与下一块。我会对其进行基准测试,因为它并不明显比仅仅连接整个事物更快,但如果你得到跨越许多块的行可能会更快。

    如果您允许任意RegExps,那么就没有更简单的解决方案了。(即使这样也不允许RegExp 使用前瞻或后瞻来检查100 个字符匹配之外的字符,甚至在更早或更晚的块中,您确实需要将内存中的整个文件作为字符串才能使这种恶作剧起作用)。

    现在,如果这样做效率太低,可能是因为某些行很大,或者某些块很小,并且您要进行大量复制来进行连接,那么我将不再使用 RegExps(和您应该使用Pattern,而不是RegExp,作为您已经接受的类型),并开始仅使用字符串或代码单元序列进行搜索。

    然后将每个传入的块扫描到末尾是有意义的,并记住你是否看到了部分分隔符,以及有多少,然后你可以继续下一个块,而不需要先在内存中组合它们在组合上运行RegExp。 它甚至允许您在传入的 bytes 中搜索分隔符,而不是先将它们转换为字符串,从而进一步减少复制开销。

    如果您允许任意字符序列作为行分隔符,那就有点棘手了。例如,使用\r\n\r\n\t作为分隔符,如果您在一个块的末尾看到\r\n\r\n,您需要能够识别下一个块的开头的\t\r\n\t。 (您可能可以为此调整 KMP string search 之类的内容,或者只是禁止使用不太简单的行分隔符)。

    如果你有一个基于状态机的RegExp 实现,将状态保持在一个块的末尾并在下一个块中继续匹配是微不足道的(ish),但是 Dart (JavaScript) @987654336 @ 不是这样的实现,它不是为进行部分匹配而构建的。 我不建议将RegExp 本身转换为与原始前缀匹配的前缀,并检测哪个前缀。仅仅因为它是very non-trivial。那是 RegExps 实际上是常规,而 Dart 不是(反向引用是非常规的)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-03-30
      • 2011-05-01
      • 1970-01-01
      相关资源
      最近更新 更多