【问题标题】:Regex to match perl variable正则表达式匹配 perl 变量
【发布时间】:2012-09-15 21:11:14
【问题描述】:

我目前正在学习正则表达式,并且正在尝试创建一个正则表达式来匹配 Perl 中的任何合法变量名。

这是我目前写的:

^\$[A-Za-z_][a-zA-Z0-9_]*

唯一的问题是正则表达式对特殊符号返回 true,例如字符串 $a& 将返回 true。

我做错了什么?

谢谢! 罗特姆

【问题讨论】:

    标签: regex perl variables


    【解决方案1】:

    解析 Perl 很困难,关于什么是变量和不是变量的规则也很复杂。如果您尝试解析 Perl,请考虑改用 PPI。它可以解析 Perl 程序并执行诸如查找所有变量之类的操作。 PPI 是 perlcritic 用来完成工作的。

    如果你还是想尝试去做,这里有一些边缘情况需要考虑......

    $^F
    $/
    ${^ENCODING}
    $1
    $élite           # with utf8 on
    ${foo}
    *{foo} = \42;
    *{$name} = \42;  # with strict off
    ${$name} = 42;   # with strict off
    

    当然还有其他印记@%*。并检测是否在单引号字符串中。这是我强烈鼓励您使用 PPI 而不是自己尝试的方式。

    如果你想练习,实际的做法是从一个更大的字符串中提取变量,而不是进行精确匹配。

    # Match the various sigils.
    my $sigils         = qr{ [\$\@\%*] }x;
    
    # Match $1 and @1 and so on
    my $digit_var      = qr{ $sigils \d+ }x;
    
    # Match normal variables
    my $named_var      = qr{ $sigils [\w^0-9] \w* }x;
    
    # Combine all the various variable matches
    my $match_variable = qr{ ( $named_var | $digit_var ) }x;
    

    这使用() 捕获操作符来抓取变量。它还使用/x 修饰符使正则表达式更易于阅读,并使用替代分隔符来避免leaning toothpick syndrome。使用\w 而不是A-Z 可确保在utf8 开启时拾取Unicode 字符,而在关闭时则不会。最后,qr 用于分段构建正则表达式。填补空白留作练习。

    【讨论】:

    • 我不打算使用我的正则表达式。我只是在学习如何编写它们,我认为变量名是一种很好的做法:)谢谢!
    • 抱歉,不知道这只是一个练习。在这种情况下,我已经更新了您如何解决此问题的良好开端。
    【解决方案2】:

    最后你需要一个$,否则它只是尽可能匹配并忽略其余部分。所以应该是:

    ^\$[A-Za-z_][A-Za-z0-9]*$
    

    【讨论】:

    • 这将匹配一个只包含一个变量的字符串。它不会匹配包含变量的字符串。
    • 看来这就是他想要的。否则,对于$a& 来说它是正确的,因为这只是一个变量,后面跟着& 运算符。但请注意,他的正则表达式以 ^ 开头,因此他希望变量位于开头。
    • 这与$17$élite 不匹配,两者都是Perl 中的合法变量名。
    • @Rotem "foo" =~ /(o+)/; print $1; @12 = (1..10); print $12[7];
    • 还有$foo::bar,或者%::
    【解决方案3】:

    我需要解决这个问题来创建一个简单的源代码分析器。
    此子例程从代码的输入部分提取 Perl 用户变量

    sub extractVars {
        my $line = shift;
        chomp $line;
        $line =~ s/#.*//;       # Remove comments
        $line =~ s/\s*;\s*$//;  # Remove trailing ;
        my @vars = ();
        my $match = 'junk';
        while ($match ne '') {
            push @vars, $match if $match ne 'junk';
            $match = ''; 
            if ($line =~ s/(
                    [\@\$\%]            # $@%
                    {?                  # optional brace
                    \$?                 # optional $
                    [\w^0-9]            # begin var name
                    [\w\-\>\${}\[\]'"]* # var name
                    [\w}\]]             # end var name
                    |
                    [\@\$\%]            # $@%
                    {?                  # optional brace
                    \$?                 # optional $
                    [\w^0-9]            # one letter var name
                    [}\]]?              # optional brace or bracket
                    )//x) {
                $match = $1;
                next;
            }
        }
        return @vars;
    }
    

    用这段代码测试它:

    my @variables = extractVars('$a $a{b} $a[c] $scalar @list %hash $list[0][1] $list[-1] $hash{foo}{bar} $aref->{foo} $href->{foo}->{bar} @$aref %$hash_ref %{$aref->{foo}} $hash{\'foo\'} "$a" "$var{abc}"');

    如果变量名包含空格,则不起作用,例如:

    • $hash{"baz qux"}
    • ${ $var->{foo} }[0]

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-01-20
      • 1970-01-01
      • 2014-07-20
      • 1970-01-01
      • 2015-07-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多