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

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

我在阅读马丁·福勒写的一篇关于Composed Regular Expressions的文章。这就是你可以使用这样的代码的地方:

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

把它分解成这样的:

  1. protected override string GetPattern() {
  2. const string pattern =
  3. @"^score
  4. \s+
  5. (\d+) # points
  6. \s+
  7. for
  8. \s+
  9. (\d+) # number of nights
  10. \s+
  11. night
  12. s? #optional plural
  13. \s+
  14. at
  15. \s+
  16. (.*) # hotel name
  17. ";
  18. return pattern;
  19. }
  20. }

或者这个:

  1. const string scoreKeyword = @"^score\s+";
  2. const string numberOfPoints = @"(\d+)";
  3. const string forKeyword = @"\s+for\s+";
  4. const string numberOfNights = @"(\d+)";
  5. const string nightsAtKeyword = @"\s+nights?\s+at\s+";
  6. const string hotelName = @"(.*)";
  7. const string pattern = scoreKeyword + numberOfPoints +
  8. forKeyword + numberOfNights + nightsAtKeyword + hotelName;

甚至是这个:

  1. const string space = @"\s+";
  2. const string start = "^";
  3. const string numberOfPoints = @"(\d+)";
  4. const string numberOfNights = @"(\d+)";
  5. const string nightsAtKeyword = @"nights?\s+at";
  6. const string hotelName = @"(.*)";
  7. const string pattern = start + "score" + space + numberOfPoints + space +
  8. "for" + space + numberOfNights + space + nightsAtKeyword +
  9. space + hotelName;

这听起来很容易做到,而且可能会带来一些好处。我决不是一个“正则表达式的家伙”,经常发现自己在网上搜索,以找到我需要的正则表达式,而不是花时间为自己编写它。在找到了一个适合给定问题的正则表达式后,我复制并粘贴它,并测试它,以确保它像广告中所说的那样。然后我可能会发表一个评论来描述它是做什么的。但之后我会去做更大更好的事情。
我想知道,以Martin Fowlers讨论中描述的方式打破正则表达式模式是否真的比注解更容易理解?在一天结束的时候,你仍然有一个丑陋的正则表达式在你的代码中,只是现在它是在许多片段。如果你需要扩展这个表达式.
我知道所有perl的死忠都喜欢他们的正则表达式模式。但是对于那些每隔一个项目只处理一次正则表达式的人来说(问题),你觉得把正则表达式模式分成更小的部分更容易理解还是更难理解?有没有人在一个项目中使用过这个概念,并发现它很有用?没用吗

wz1wpwve

wz1wpwve1#

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

qzlgjiam

qzlgjiam2#

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

  1. /^
  2. score \s+ (\d+) \s+
  3. for \s+ (\d+) \s+
  4. nights? \s+ at \s+ (.*)
  5. /x

我个人更喜欢Perl 6风格的正则表达式。我觉得它们更容易读懂。

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

在对该规则执行匹配之后,$/将与匹配的文本相关联。
比如说

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

会输出这样的东西

  1. Hotel name of hotel
  2. {
  3. 'hotel' => 'name of hotel',
  4. 'nights' => 5,
  5. 'score' => 8
  6. }
展开查看全部
jk9hmnmh

jk9hmnmh3#

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

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

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

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

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

相关问题