逻辑条件/数学表达式验证

时间:2014-04-15 14:35:42

标签: regex perl

我想验证一个字符串,它包含一个像

这样的表达式
isFun && ( isHelpful || isUseful )

这些表达式可以包含操作数,二元运算符和一元运算符:

my $unary_operator  = qr/(?:\+|\-|!|not)/;
my $binary_operator = qr/(?:<|>|<=|>=|==|\!\=|<=>|\~\~|\&|\||\^|\&\&|\|\||lt|gt|le|ge|and|or|xor|eq|ne|cmp)/i;
my $operand         = qr/[a-z0-9_]+/i;

它们与你从perl的条件模式中所知道的类似(例如在if语句中)。括号必须是平衡的,一元运算符只能连续使用一次。

我想找到一个perl兼容的正则表达式,它确保有一个有效的逻辑/数学表达式,其中只使用给定的运算符,操作数与$operand给出的正则表达式匹配。通过递归,这在perl中是可能的。该声明采用中缀表示法。

我目前的解决方案是解析树并执行一些迭代,但我想将此算法压缩为单个正则表达式。

对于我的第一次尝试(我仍然排除了所有详细的操作数),我使用了

my $re =
qr{
    ( # 1
        ( # 2 operands ...
            $operand
        )
        |
        ( # 3 unary operators with recursion for operand
            (?:$unary_operator(?!\s*$unary_operator)\s*(?1))
        )
        |
        ( # 4 balance brackets
            \(
                \s*(?1)\s*
            \)
        )
        |
        ( # 5 binary operators with recursion for each operand
            (?1)\s*$binary_operator\s*(?1)
        )
    )
}x;

...最终以无限递归结束。我认为递归可能是在括号5中使用第一个(?1)引起的。

有人在那里有一个有效的解决方案吗?

1 个答案:

答案 0 :(得分:0)

以下内容适用于验证表达式:

use strict;
use warnings;

my $unary_operator  = qr/(?:\+|\-|!|not)/;
my $binary_operator = qr/(?:<|>|<=|>=|==|\!\=|<=>|\~\~|\&|\||\^|\&\&|\|\||lt|gt|le|ge|and|or|xor|eq|ne|cmp)/i;
my $operand         = qr/[a-z0-9_]+/i;

my $re =
qr{^
    ( # 1
        \s*
        (?> (?:$unary_operator \s*)* )
        (?:
             \b$operand\b
        |
             \( (?1) \)
        )
        (?:
            \s*
            $binary_operator
            \s*
            (?1)
        )*
        \s*
    )
$}x;

while (<DATA>) {
    chomp;
    my ($expr, $status) = split "#", $_, 2;

    if ($expr =~ $re) {
        print "good  $_\n";
    } else {
        print "bad   $_\n";
    }

}

__DATA__
isFun                                    # Good
isFun && isHelpful                       # Good
isFun && isHelpful || isUseful           # Good
isFun && ( isHelpful || isUseful )       # Good
isFun && ( isHelpful || (isUseful) )     # Good
isFun && ( isHelpful || (isUseful )      # Fail - Missing )
not (isFun && (isHelpful || (isBad && isDangerous)))  # Good
isGenuine!isReal                         # Fail
!isGenuine isReal                        # Fail

输出:

good  isFun                                    # Good
good  isFun && isHelpful                       # Good
good  isFun && isHelpful || isUseful           # Good
good  isFun && ( isHelpful || isUseful )       # Good
good  isFun && ( isHelpful || (isUseful) )     # Good
bad   isFun && ( isHelpful || (isUseful )      # Fail - Missing )
good  not (isFun && (isHelpful || (isBad && isDangerous)))  # Good
bad   isGenuine!isReal                         # Fail
bad   !isGenuine isReal                        # Fail