【问题标题】:Using Regex to efficiently parse/lex tokens使用 Regex 有效地解析/lex 标记
【发布时间】:2014-03-06 17:15:34
【问题描述】:

我正在尝试找到一种在 .NET 中使用正则表达式的方法来有效地确定字符串匹配的几种模式中的哪一种。如果我的标记是固定文本,我会使用 Dictionary 并简单地查找它们。但是,令牌中可能嵌入了一个或多个数字序列来表示索引。我有几十到 100 个这样的令牌。举个小例子,我想匹配以下标记之一:

ORDERID
PRICE(\d+)
QUANTITY(\d+)
DESCRIPTION(\d+)
WEIGHT(\d+)_(\d+)

(想象的用例是我有一组名称-值对,名称使用嵌入的整数来允许重复。在这个例子中,想象一个有多行的订单,PRICE 是第 n 行的价格. WEIGHT_ 是第 n 行的第 m 个单个对象的权重(假设 lineitem 是某种工具包)。

请注意,这些令牌的组成不在我的控制范围内。

我可以用类似的东西有效地识别这些标记

^(?<oid>ORDERID)|(?<prc>PRICE(\d+))|(?<qty>QUANTITY(\d+)|(?<dsc>DESCRIPTION(\d+)|(?<wght>WEIGHT(\d+)_(\d+)$

请注意,给定正则表达式的正则表达式匹配与您要匹配的字符串的大小成线性关系,并且当我添加更多标记时,它的效率不应超过 log n。

现在做一场比赛:

Match m = r.Match("PRICE44")

不幸的是,据我所知,要确定哪个标记与 Regex.Match 对象匹配,我必须遍历所有可能性:

m.Groups["oid"].Success
m.Groups["prc"].Success
m.Groups["qty"].Success
m.Groups["dsc"].Success
m.Groups["wght"].Success

随着代币数量的增加,成本呈线性增长(或更可能是 n log n)。如果有,比如说,一个 SuccessGroups 集合,我可以遍历它,它通常(在我的使用中)有一个元素:匹配的特定组。

我可以编写自己的解析算法来创建 trie 或类似的数据结构,但我不愿意重新实现 Regex 已经实现但似乎无法让我有效访问的东西。

有什么想法或建议吗?

【问题讨论】:

  • 与执行正则表达式迭代组列表的成本相比应该没有意义吧?您的基准测试显示了什么?
  • 不对。匹配一个预编译的正则表达式实际上是非常有效的:它是一个确定性的有限状态自动机,它的执行在被匹配的输入字符串的长度上近似线性(如果你愿意节省空间,它可以是严格线性的,但是您通常会使用更节省空间的结构来确定给定输入字符的下一个状态,这可以与可能的下一个字符数成线性关系,也可以在下一个字符数中记录 n。
  • 我用我需要识别的 80 个令牌做了一个简单的测试。我只进行了匹配,然后进行了匹配,然后遍历组以找到成功的组。遍历组的成本大约等于实际识别的成本,即加起来是两倍的时间。我发现一个匹配平均耗时约 3.6uS,搜索结果耗时约 7.5uS。
  • 我看不到任何使用可用 API 的方法。它没有在 Group 类上公开组名,这很糟糕。这将解决您的问题,因为这些组是按照捕获顺序返回的。

标签: c# .net regex vb.net performance


【解决方案1】:

也许使用组,它会记录第一个匹配的,你可以遍历匹配而不是标记 http://msdn.microsoft.com/en-us/library/bs2twtah%28v=vs.110%29.aspx#matched_subexpression

【讨论】:

  • 正则表达式中的每个组都有一个可能匹配的组。遍历组与我们识别的令牌数量成线性关系。正则表达式引擎已经识别出匹配的标记,我只想有效地提取该信息。
猜你喜欢
  • 2011-12-29
  • 2012-05-16
  • 2019-04-28
  • 1970-01-01
  • 2019-06-03
  • 2018-01-26
  • 1970-01-01
  • 2020-10-11
  • 1970-01-01
相关资源
最近更新 更多