如何使perl正则表达式选项有条件

时间:2011-02-28 17:09:23

标签: regex perl

不要问为什么,但......

我有一个正则表达式,如果在Windows上运行需要不区分大小写,但在* nix上运行时区分大小写。

以下是我目前正在做的事情的一个示例摘录。

sub relative_path 
{
    my ($root, $path) = @_;

    if ($os eq "windows")
    {
        # case insensitive with regex option 'i'
        if ($path !~ /^\Q$root\E[\\\/](.*)$/i)
        {
            print "\tFAIL:$root not in $path\n";
        }
        else
        {
            return $1;
        }
    }
    else
    {
        # case sensitive
        if ($path !~ /^\Q$root\E[\\\/](.*)$/)
        {
            print "\tFAIL:$root not in $path\n";
        }
        else
        {
            return $1;
        }
    }
    return "";
}

哎呀!重复会伤害我的强迫症,但我的perl-fu很弱。不知怎的,我想让正则表达式选项'i'用于不区分大小写的条件,但我现在不怎么样?

4 个答案:

答案 0 :(得分:9)

您可以使用扩展构造来指定选项。例如:

#!/usr/bin/env perl

use warnings; use strict;

my $s = 'S';

print check($s, 'i'), "\n";
print check($s, '-i'), "\n";

sub check {
    my ($s, $opt) = @_;
    return "Matched" if $s =~ /(?$opt)^s\z/;
    return "Did not match";
}

请参阅perldoc perlre

答案 1 :(得分:5)

您可以使用qr运算符创建模式并将其存储在标量中:

sub relative_path 
{
    my ($root, $path) = @_;

    my $pattern = ($os eq "windows") ? qr/^\Q$root\E[\\\/](.*)$/i : qr/^\Q$root\E[\\\/](.*)$/;

    if ($path !~ $pattern)
    {
        print "\tFAIL:$root not in $path\n";
    }
    else
    {
        return $1;
    }
}

这可能不是100%完美,但希望你能得到这个想法。

请务必查看"Quote and Quote-Like Operators" in perlop部分。


编辑:好的,这是一个干燥的解决方案,因为人们在抱怨它。

sub relative_path 
{
    my ($root, $path) = @_;

    my $base_pattern = qr/^\Q$root\E[\\\/](.*)$/;
    my $pattern = ($os eq "windows") ? qr/$base_pattern/i : $base_pattern;

    if ($path !~ $pattern)
    {
        print "\tFAIL:$root not in $path\n";
    }
    else
    {
        return $1;
    }
}

答案 2 :(得分:4)

除了实现既定目标外,这还可以正确处理卷,而不像以前发布的正则表达式模式。

use Path::Class qw( dir );

sub relative_path {
   my ($root, $path) = @_;

   if ($^O =~ /Win32/) {
      require Win32;
      $root = Win32::GetLongPathName($root);
      $path = Win32::GetLongPathName($path);
   }

   $root = dir($root);
   $path = dir($path);

   if ($root->subsumes($path)) {
      return $path->relative($root);
   } else {
      print "\tFAIL:$root not in $path\n";
      return "";
   }
}

顺便说一句,在那里处理错误并不合适。该函数应该返回一个错误信号(返回undef,抛出异常等),调用者应该按照它认为合适的方式处理它。关注点分离。

答案 3 :(得分:1)

您也可以使用局部修饰符(perl扩展正则表达式选项)来执行此操作:

sub relative_path 
{
    my ($root, $path) = @_;

    my $pattern = "^\Q$root\E[\\\/](.*)$";
    $pattern = "(?i)$pattern" if ($os eq "windows");
    if ($path =~ /$pattern/)
    {
        return $1;
    }
    else
    {
        print "\tFAIL:$root not in $path\n";
    }
}

(在我输入我的答案后,我看到思南也提出了这个建议,但我也决定发布我的答案,因为它给出了一个更具体的答案)