2

我在 Perl 中匹配正则表达式时遇到问题,想知道是否有人有任何见解:

这是我的正则表达式:/^-MEMBER:\s+(\b[^,]+)(?:,\s(\b.{1,50}\b)\.?)?\s+ID#:\s+(\d+)$/

这是我匹配的内容:

-成员:Doe,John H ID#:3907

正则表达式工作得很好,并且与上面的行匹配,但是对于任何可能不包含名字和中间名的行都有问题。下面的例子:

-成员:Doe,ID#:3907

我无法匹配当前的正则表达式,这两行。

谢谢你的帮助!

4

3 回答 3

1

您已将逗号匹配放在可选的名字组中,因此您只能在存在名字的情况下匹配逗号。如果逗号将伴随没有名字的姓氏,则需要将其移至姓氏组。

/^-MEMBER:\s+(\b[^,]+,)(?:\s(\b.{1,50}\b)\.?)?\s+ID#:\s+(\d+)$/
于 2013-03-14T17:49:48.430 回答
0

问题在于,你真正用的是什么语法来描述你的输入。试图一口气描述这一切变得非常复杂,非常快。请参阅 perl yapp 模块以获取替代方案。

但是,如果您坚持只使用正则表达式,那么我们开始:

/^-MEMBER: # start of line, match specific string
\s+ # must be followed by at least one whitespace char
(\b[^,]+) # now we need to match a word in a capture group
(?:,\s(\b.{1,50}\b)\.?)? # here's the pain, so lets deal with it below
\s+ # more whitespace
ID#: # match this string
\s+ # and some more whitespace
(\d+)$/ # digits at the end of the line

(
 ?: # cluster the following
 ,\s # comma, then a single space
 (
  \b.{1,50}\b # up to fifty "things" bounded by words
 ) # another capture group
 \.? # optional period
)? # zero or one of these I.E. optional capture

这是脆弱的,因为它将假设硬编码到您的“语言”中。请注意,如果我们没有名字/中间名,则不允许使用逗号,因为它位于可选组内。那是您的第二次测试不匹配的问题。

其次,如果我们有一个名字/中间名部分,它可以包含除换行符之外的任何内容。这可能不是您想要或期望的。

解析器有用的原因不一定是因为它们允许您拥有“上下文”,尽管它们这样做了。这是因为它将你复杂的正则表达式分解成小的、易于管理的部分,它们连接在一起形成一个明确定义的整体。通过学习这样的工具,您在这里遇到的问题类型变得容易实现和改变

请注意您的正则表达式如何尝试定义每个部分中的“有效”内容。姓氏(\b[^,]+)可以有除逗号以外的任何内容!这是你想要的吗?如果有效名称只能包含[a-zA-Z_]在其中会发生什么?是;injectionattemptFTW!!;#一个有效的名字吗?设计您的程序,以便有一组有限且明显的条件。If a then valid, else fail对于简单a的 s 很容易推理。

除非您定义所有可能的特殊情况,否则您将遇到导致此正则表达式中断的事情。我无法定义完美的正则表达式,因此您有两种选择:

  1. 随着特殊情况的识别,将正则表达式修补为更加复杂的
  2. 重新设计以避免需要复杂的正则表达式

如果您选择选项一,那么这个正则表达式可以解决您当前的问题:

/^-MEMBER:\s+(\b[^,]+),?(?:\s(\b.{1,50}\b)\.?)?\s+ID#:\s+(\d+)$/
于 2013-03-14T17:58:13.443 回答
0

此正则表达式将匹配两行:

/
    ^-MEMBER:\s+         # the beginning of the line with "-MEMBER: "
    .*?                  # non greedy
    \s+ID#:\s+(\d+)$     # space and end ID part
/x
于 2013-03-14T17:39:41.573 回答