【问题标题】:Logical condition / math expression validation逻辑条件/数学表达式验证
【发布时间】:2014-04-16 14:49:56
【问题描述】:

我想验证一个字符串,它包含一个类似的表达式

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) 引起的。

有人有可行的解决方案吗?

【问题讨论】:

    标签: regex perl


    【解决方案1】:

    以下内容应该适用于验证您的表达式:

    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
    

    【讨论】:

    • 嘿米勒!这很接近,但它会为isGenuine!isReal!isGenuine isReal 返回误报。我认为会发生这种情况,因为ne 将操作员作为isGeniune 的一部分。我在运算符集中用\bne\b 替换了ne(和所有其他详细运算符)来解决这个问题,但我更喜欢一个可以处理上述问题中给出的运算符集的解决方案。你觉得这可能吗?
    • 是的,这更多是您的正则表达式的问题,但可以通过在操作数周围添加单词边界来解决:\b$operand\b
    • 好的,操作数周围的单词边界显然比运算符周围更有意义!谢谢! yourAnswer == ( isAwesome &amp;&amp; isHelpful ):D
    猜你喜欢
    • 1970-01-01
    • 2018-11-03
    • 1970-01-01
    • 1970-01-01
    • 2014-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多