0

我正在阅读 Martin Fowler 撰写的一篇关于Composed Regular Expressions的文章。这是您可以使用如下代码的地方:

const string pattern = @"^score\s+(\d+)\s+for\s+(\d+)\s+nights?\s+at\s+(.*)";

并把它分解成更像这样的东西:

protected override string GetPattern() {
      const string pattern =
        @"^score
        \s+  
        (\d+)          # points
        \s+
        for
        \s+
        (\d+)          # number of nights
        \s+
        night
        s?             #optional plural
        \s+
        at
        \s+
        (.*)           # hotel name
        ";

      return pattern;
    }
  }

或这个:

const string scoreKeyword = @"^score\s+";
const string numberOfPoints = @"(\d+)";
const string forKeyword = @"\s+for\s+";
const string numberOfNights = @"(\d+)";
const string nightsAtKeyword = @"\s+nights?\s+at\s+";
const string hotelName = @"(.*)";

const string pattern =  scoreKeyword + numberOfPoints +
  forKeyword + numberOfNights + nightsAtKeyword + hotelName;

甚至这样:

const string space = @"\s+";
const string start = "^";
const string numberOfPoints = @"(\d+)";
const string numberOfNights = @"(\d+)";
const string nightsAtKeyword = @"nights?\s+at";
const string hotelName = @"(.*)";

const string pattern =  start + "score" + space + numberOfPoints + space +
  "for" + space + numberOfNights + space + nightsAtKeyword + 
   space + hotelName;

这听起来很容易做到,并且可能有一些好处。我绝不是一个“正则表达式的人”,并且经常发现自己在网上搜索以找到我需要的正则表达式,而不是花时间为自己编写它。找到适合给定问题的正则表达式后,我将其复制并粘贴并对其进行测试以确保它与宣传的一样。然后我可能会发表评论来描述它的作用。但后来我开始了生活中更大更好的事情。

我想知道以 Martin Fowlers 讨论中描述的方式打破正则表达式模式是否真的会让事情比评论更容易理解?归根结底,您的代码中仍然有一个丑陋的正则表达式,只是现在它有很多部分。如果您需要扩展该表达式……这如何帮助您真正理解正则表达式的作用?

我知道所有顽固的 perl 人都喜欢他们的正则表达式模式。但是对于那些在每个其他项目(问题)中不多次处理正则表达式的人来说,您是否发现将正则表达式模式分解成更小的位或多或少的可读性?有没有人在项目中使用过这个概念并发现它很有用?...没用处?

4

3 回答 3

2

是的,一点没错。正则表达式功能强大,但由于其简洁的语法,极难阅读。当我阅读诸如“这与 URI 匹配”之类的评论时,这实际上并不能帮助我弄清楚它是如何做到的,以及我应该在哪里(例如)修复一个与某个不起眼的角落不匹配的错误查询字符串中的大小写正确。正则表达式是代码;像记录函数一样记录它。如果它简短且(合理)清晰,则整个正则表达式的单个注释都可以。如果它很复杂,请清楚地突出显示和注释各个部分。如果它真的很复杂,请将其拆分为几个正则表达式。

于 2009-07-24T23:43:01.377 回答
0

如果您可以使用扩展语法,则相当容易阅读。

/^
  score   \s+ (\d+) \s+
  for     \s+ (\d+) \s+
  nights? \s+  at   \s+ (.*)
/x

我个人更喜欢 Perl 6 风格的正则表达式。我认为它们更容易阅读。

rule pattern{
  score        $<score>= [ <.digits>+ ]
  for          $<nights>=[ <.digits>+ ]
  night[s]? at $<hotel>= [ .+ ]
}

在您针对该规则执行匹配后,$/将与匹配的文本相关联。

所以是这样的:

say "Hotel $/<hotel>";
say $/.perl;

会输出这样的东西

Hotel name of hotel
{
  'hotel'  => 'name of hotel',
  'nights' => 5,
  'score'  => 8
}
于 2009-07-25T01:05:48.803 回答
0

我在 PHP 中通过使用关联数组和 PHP 版本的 tr 函数来处理这个问题(我假设任何语言中都存在类似的数据结构和函数)。

数组如下所示:

$mappings = array ( 
  'a' => '[a-z0-9]',
  'd' => '[0-9]', 
  's' => '\s+', //and so on 
);

然后当我使用它们时,只需与 tr 函数合并即可。映射的东西被转换,而未映射的东西则落空:

 $regexp = strtr( $simplified_string, $mappings) ;

请记住,这种方法很容易使事情变得过于复杂,因为它可以简化它们。您仍在写出模式,只是您将一种模式抽象为另一种模式。尽管如此,拥有这些穷人的字符类对于将正则表达式外包给不会说该语言的开发人员或规范提供者很有用。

于 2009-07-25T01:28:29.567 回答