regex 复合正则表达式-将正则表达式分解为可读形式

mmvthczy  于 2023-10-22  发布在  其他
关注(0)|答案(3)|浏览(112)

我在阅读马丁·福勒写的一篇关于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的死忠都喜欢他们的正则表达式模式。但是对于那些每隔一个项目只处理一次正则表达式的人来说(问题),你觉得把正则表达式模式分成更小的部分更容易理解还是更难理解?有没有人在一个项目中使用过这个概念,并发现它很有用?没用吗

wz1wpwve

wz1wpwve1#

是的,当然。正则表达式功能强大,但由于其简洁的语法,非常难以阅读。当我读到诸如“this matches an URI”这样的评论时,这实际上并不能帮助我弄清楚它是如何做到这一点的,以及我应该在哪里寻找(例如)修复一个错误,它不能正确匹配查询字符串中的一些模糊的角落情况。Regex是代码;像记录函数一样记录它。如果它很短并且(合理地)清晰,整个正则表达式的单个注解就可以了。如果它很复杂,清楚地突出显示并注解各个部分。如果它真的很复杂,把它分成几个正则表达式。

qzlgjiam

qzlgjiam2#

如果你能扩展语法的话,它是相当容易阅读的。

/^
  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
}
jk9hmnmh

jk9hmnmh3#

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

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

然后当我使用它们时,只需要与tr函数合并即可。Map的内容被转换,未Map的内容福尔斯通过:

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

请记住,这种方法很容易使事情变得过于复杂,因为它可以简化它们。你仍然在写模式,只是你把一个模式抽象成了另一个。尽管如此,拥有这些穷人的字符类在将regexp外包给不会说这种语言的开发人员或规范提供商时还是很有用的。

相关问题