regex to match irreducible fractions

后端 未结 4 1014
野的像风
野的像风 2021-02-04 01:11

How can I match irreducible fractions with regex?

For example, 23/25, 3/4, 5/2, 100/101, etc.

First of all, I have no idea about the gcd-algorithm realization in

4条回答
  •  长发绾君心
    2021-02-04 01:57

    UPDATE

    Since the poster requested a single regex that matches against strings like "36/270", but says it doesn’t matter how legible it is, that regex is:

    my $reducible_rx = qr{^(\d+)/(\d+)$(?(?{(1x$1."/".1x$2)=~m{^(?|1+/(1)|(11+)\1*/\1+)$}})|^)};
    

    But, if like me, you believe that an illegible regex is absolutely unacceptable, you will write that more legibly as:

    my $reducible_rx = qr{
      # first match a fraction:
        ^ ( \d+ ) / ( \d+ ) $
      # now for the hard part:
        (?(?{ ( 1 x $1 . "/" . 1 x $2 ) =~ m{
                    ^
                    (?|    1+      / (1)  # trivial case: GCD=1
                      |  (11+) \1* / \1+  # find the GCD
                    )
                     $
                }x
            })
              # more portable version of (*PASS)
         | ^  # more portable version of (*FAIL)
         )
    }x;
    

    You can improve maintainability by splitting out the version that matches the unary version from the one that matches the decimal version like this:

    # this one assumes unary notation
    my $unary_rx = qr{
        ^ 
        (?|   1+       / (1)
          | (11+)  \1* / \1+ 
        ) 
        $
    }x;
    
    # this one assumes decimal notation and converts internally
    my $decimal_rx = qr{
      # first match a fraction:
        ^ ( \d+ ) / ( \d+ ) $ 
      # now for the hard part:
        (?(?{( 1 x $1 . "/" . 1 x $2 ) =~ $unary_rx})
              # more portable version of (*PASS)
         | ^  # more portable version of (*FAIL) 
         )
    }x;
    

    Isn’t that much easier by separating it into two named regexes? That would now make $reducible_rx the same as $decimal_rx, but the unary version is its own thing. That’s how I would do it, but the original poster wanted a single regex, so you’d have to interpolate the nested one for that as I first present above.

    Either way, you can plug into the test harness below using:

        if ($frac =~ $reducible_rx) {
            cmp_ok($frac, "ne", reduce($i, $j), "$i/$j is $test");
        } else {
            cmp_ok($frac, "eq", reduce($i, $j), "$i/$j is $test");
        }
    

    And you will see that it is a correct regex that passes all tests, and does so moreover using a single regex, wherefore having now passed all requirements of the original question, I declare Qᴜᴏᴅ ᴇʀᴀᴛ ᴅᴇᴍᴏɴsᴛʀᴀɴᴅᴜᴍ: “Quit, enough done.”

提交回复
热议问题