DBI.pm中的这一行有什么作用?

时间:2011-07-13 09:48:47

标签: regex perl

603   $dsn =~ s/^dbi:(\w*?)(?:\((.*?)\))?://i
                         or '' =~ /()/; # ensure $1 etc are empty if match fails

我不明白$dsn =~ s/^dbi:(\w*?)(?:\((.*?)\))?://i是什么,对'' =~ /()/更加怀疑,对我来说似乎毫无用处。

5 个答案:

答案 0 :(得分:4)

第一部分是以下列形式提取dsn字符串的两部分:

dbi:第一场比赛可选的第二场比赛):

这些匹配将放入$1$2,以便在以后的代码中使用。第二部分仅在比赛失败时才会运行。这是通过使用or来实现的,如果第一个表达式成功,它将使第二个表达式短路(即不执行)。

正如评论所说的那样,它确保$1$2等是空的。据推测,如果没有设置(即无法从dsn字符串中提取),代码可以检查它们并产生适当的错误。

答案 1 :(得分:1)

Equals-tilde或=~match operator

尝试以下代码 - 将其放入文件中,使用chmod +x生成可执行文件并运行它:

#!/usr/bin/perl

$mystring = "Perl rocks.";

if ($mystring =~ /rocks/) {
  print("Matches");
} else {
  print("No match");
}

它将输出Matches

至于你的例子,它检查连接字符串是否格式正确,并提取数据库名称等:

print($dsn);

$dsn = "dbi:SQLPlatform:database_name:host_name:port";

$dsn =~ s/^dbi:(\w*?)(?:\((.*?)\))?://i
                             or '' =~ /()/; # ensure $1 etc are empty if match fails

print($dsn);

Ouptuts database_name:host_name:port

答案 2 :(得分:1)

从代码中的评论中可以清楚地看出:

602     # extract dbi:driver prefix from $dsn into $1
603     $dsn =~ s/^dbi:(\w*?)(?:\((.*?)\))?://i
604             or '' =~ /()/; # ensure $1 etc are empty if match fails

如果您在了解s//m//的工作方式时遇到问题,请参阅perlopperlre

答案 3 :(得分:0)

如果捕获匹配失败,$ 1仍可能包含值;在同一动态范围中最后一次成功匹配捕获的值,可能来自其他一些以前的正则表达式。看来作者不希望此时失败的匹配在前一个正则表达式中留下1美元的价值。为了防止这种情况,他强迫“将永远成功”捕获匹配捕获内容中指定的任何内容。这意味着将有一个匹配,并捕获空字符串。换句话说,$ 1现在将为空,而不是包含先前成功匹配的匹配值。

更常见的习惯用法是在执行任何依赖于$ 1值的代码之前测试匹配成功,如:

if( /(match)/ ) {
    say $1;
}

虽然这通常是最简单的方法,但遗憾的是代码有时并不简单,并且将测试强制转换为某些复杂的代码可能会使棘手的部分更难以处理。在这种情况下,可能更容易确保$ 1在匹配失败后不包含任何内容,而不是在失败的匹配之前包含的内容。

我实际上认为这是一个很好的问题。在Perl POD中找到失败匹配后#$ 1行为的文档并不容易。我相信在骆驼书或骆驼书中可以找到更彻底的解释。但我现在还没有触手可及的检查。

答案 4 :(得分:0)

到目前为止,答案中遗漏的是这个神秘or '' =~ /()/的原因。如果没有那么棘手,如果匹配失败,$ 1将是未定义的。代码可能在串联后使用$ 1或在此匹配后不久使用字符串。使用$ 1 undefined执行此操作将导致“在use warnings生效时使用未连接值$ 1连接(。)或字符串”警告。使用or '' =~ /()/技巧,如果正则表达式无法匹配,将定义$ 1(但为空)。这使得使用$ 1喷出的代码保持不变。

评论# ensure $1 etc are empty if match fails不正确。摆脱'等',评论是正确的。此操作设置$ 1和$ 1。此代码未设置$ 2。如果正则表达式不匹配,$ 2将是未定义的。