gpt4 book ai didi

regex - 正则表达式以匹配不可约分数

转载 作者:行者123 更新时间:2023-12-03 11:34:12 24 4
gpt4 key购买 nike

如何将irreducible fractions与正则表达式匹配?

例如23 / 25、3 / 4、5 / 2、100 / 101等。

首先,我对正则表达式中的gcd-algorithm实现一无所知。

为所有回答“例如您使用错误的工具”的人更新:

是的,伙计们,我意识到正则表达式通常用于什么目的。没关系。但是这个问题很奇怪,这是它的全部要点。

更新2:的想法是找到一个在以下情况下可能有用的正则表达式:

$> echo "1/2" | grep -P regex
1/2
$> echo "2/4" | grep -P regex

因此,正则表达式只能是一个字符串,而不使用任何脚本和变量。只有正则表达式。

实际上,我已经知道一些正则表达式,它们匹配一元数系统中写的可约分数。
$> echo "11/1111" | grep -P '^1/1+$|(11+)+\1+/\1+$'
11/1111

因此,事情是在正则表达式中从十进制转换为一进制数,但我不知道如何。

最佳答案

更新

由于发布者要求的单个正则表达式与“36/270”之类的字符串相匹配,但是说它的可读性并不重要,因此该正则表达式为:

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

但是,如果像我一样,您认为难以理解的正则表达式是绝对不能接受的,那么您将更清楚地写为:
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;

通过将与一进制版本匹配的版本从与十进制版本匹配的版本中分离出来,可以提高可维护性:
# 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;

将它分成两个命名的正则表达式难道不是很容易吗?现在,这会使 $reducible_rx$decimal_rx相同,但是一元版本是其自身的事情。我就是这样做的,但是原始的海报只需要一个正则表达式,因此您必须在上面第一次插入时为它嵌套一个正则表达式。

无论哪种方式,都可以使用以下方法插入下面的测试工具:
    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");
}

您会发现它是通过所有测试的正确正则表达式,而且使用单个正则表达式也是如此,因此,现在已经通过了原始问题的所有要求,我声明Qᴜᴏᴅs“:“退出,已完成。” 😇

不用客气。

答案是,一旦将正则表达式 ^(?|1+/(1)|(11+)\1*/\1+)$从十进制转换为一元符号,就将其与分数匹配,此时,在匹配项中的 $1中将找到最大的公因数;否则它们是互质的。如果您使用的是Perl 5.14或更高版本,则甚至可以一步完成此操作:
use 5.014;
my $reg = qr{^(?|1+/(1)|(11+)\1*/\1+)$};
my $frac = "36/270"; # for example
if ($frac =~ s/(\d+)/1 x $1/reg =~ /$reg/) {
say "$frac can be reduced by ", length $1;
} else {
say "$frac is irreducible";
}

哪个将正确报告:
36/270 can be reduced by 18

(当然,减1意味着不再有分母。)

如果您想和您的读者一起开心一点,您甚至可以这样做:
use 5.014;
my $regex = qr{^(?|1+/(1)|(11+)\1*/\1+)$};
my $frac = "36/270"; # for example
if ($frac =~ s/(\d+)/"1 x $1"/regex =~ /$regex/) {
say "$frac can be reduced by ", length $1;
} else {
say "$frac is irreducible";
}

这是演示如何执行此操作的代码。此外,它构造了一个测试套件,使用所有(正)分子和分母(不超过其参数)或默认值为30来测试其算法。要在测试工具下运行它,请将其放入名为coprimes的文件中,然后执行以下操作:
$ perl -MTest::Harness -e 'runtests("coprimes")'
coprimes .. ok
All tests successful.
Files=1, Tests=900, 1 wallclock secs ( 0.13 usr 0.02 sys + 0.33 cusr 0.02 csys = 0.50 CPU)
Result: PASS

这是在没有测试工具的情况下运行时其输出的示例:
$ perl coprimes 10
1..100
ok 1 - 1/1 is 1
ok 2 - 1/2 is 1/2
ok 3 - 1/3 is 1/3
ok 4 - 1/4 is 1/4
ok 5 - 1/5 is 1/5
ok 6 - 1/6 is 1/6
ok 7 - 1/7 is 1/7
ok 8 - 1/8 is 1/8
ok 9 - 1/9 is 1/9
ok 10 - 1/10 is 1/10
ok 11 - 2/1 is 2
ok 12 - 2/2 is 1
ok 13 - 2/3 is 2/3
ok 14 - 2/4 is 1/2
ok 15 - 2/5 is 2/5
ok 16 - 2/6 is 1/3
ok 17 - 2/7 is 2/7
ok 18 - 2/8 is 1/4
ok 19 - 2/9 is 2/9
ok 20 - 2/10 is 1/5
ok 21 - 3/1 is 3
ok 22 - 3/2 is 3/2
ok 23 - 3/3 is 1
ok 24 - 3/4 is 3/4
ok 25 - 3/5 is 3/5
ok 26 - 3/6 is 1/2
ok 27 - 3/7 is 3/7
ok 28 - 3/8 is 3/8
ok 29 - 3/9 is 1/3
ok 30 - 3/10 is 3/10
ok 31 - 4/1 is 4
ok 32 - 4/2 is 2
ok 33 - 4/3 is 4/3
ok 34 - 4/4 is 1
ok 35 - 4/5 is 4/5
ok 36 - 4/6 is 2/3
ok 37 - 4/7 is 4/7
ok 38 - 4/8 is 1/2
ok 39 - 4/9 is 4/9
ok 40 - 4/10 is 2/5
ok 41 - 5/1 is 5
ok 42 - 5/2 is 5/2
ok 43 - 5/3 is 5/3
ok 44 - 5/4 is 5/4
ok 45 - 5/5 is 1
ok 46 - 5/6 is 5/6
ok 47 - 5/7 is 5/7
ok 48 - 5/8 is 5/8
ok 49 - 5/9 is 5/9
ok 50 - 5/10 is 1/2
ok 51 - 6/1 is 6
ok 52 - 6/2 is 3
ok 53 - 6/3 is 2
ok 54 - 6/4 is 3/2
ok 55 - 6/5 is 6/5
ok 56 - 6/6 is 1
ok 57 - 6/7 is 6/7
ok 58 - 6/8 is 3/4
ok 59 - 6/9 is 2/3
ok 60 - 6/10 is 3/5
ok 61 - 7/1 is 7
ok 62 - 7/2 is 7/2
ok 63 - 7/3 is 7/3
ok 64 - 7/4 is 7/4
ok 65 - 7/5 is 7/5
ok 66 - 7/6 is 7/6
ok 67 - 7/7 is 1
ok 68 - 7/8 is 7/8
ok 69 - 7/9 is 7/9
ok 70 - 7/10 is 7/10
ok 71 - 8/1 is 8
ok 72 - 8/2 is 4
ok 73 - 8/3 is 8/3
ok 74 - 8/4 is 2
ok 75 - 8/5 is 8/5
ok 76 - 8/6 is 4/3
ok 77 - 8/7 is 8/7
ok 78 - 8/8 is 1
ok 79 - 8/9 is 8/9
ok 80 - 8/10 is 4/5
ok 81 - 9/1 is 9
ok 82 - 9/2 is 9/2
ok 83 - 9/3 is 3
ok 84 - 9/4 is 9/4
ok 85 - 9/5 is 9/5
ok 86 - 9/6 is 3/2
ok 87 - 9/7 is 9/7
ok 88 - 9/8 is 9/8
ok 89 - 9/9 is 1
ok 90 - 9/10 is 9/10
ok 91 - 10/1 is 10
ok 92 - 10/2 is 5
ok 93 - 10/3 is 10/3
ok 94 - 10/4 is 5/2
ok 95 - 10/5 is 2
ok 96 - 10/6 is 5/3
ok 97 - 10/7 is 10/7
ok 98 - 10/8 is 5/4
ok 99 - 10/9 is 10/9
ok 100 - 10/10 is 1

这是程序:
#!/usr/bin/env perl
#
# coprimes - test suite to use unary coprimality algorithm
#
# Tom Christiansen <tchrist@perl.com>
# Sun Apr 17 12:18:19 MDT 2011

use strict;
use warnings;

my $DEFAULT = 2*3*5;
my $max = @ARGV ? shift : $DEFAULT;

use Test::More;
plan tests => $max ** 2;

my $rx = qr{
^
(?| 1+ / (1)
| (11+) \1* / \1+
)
$
}x;

for my $i ( 1 .. $max ) {
for my $j ( 1 .. $max ) {
my $test;
if (((1 x $i) . "/" . (1 x $j)) =~ /$rx/) {
my $cf = length($1);
$test = $i / $cf;
$test .= "/" . $j/$cf unless $j/$cf == 1;
} else {
$test = "$i/$j";
}
cmp_ok($test, "eq", reduce($i, $j), "$i/$j is $test");
}
}

sub reduce {
my ($a, $b) = @_;
use Math::BigRat;
my $f = new Math::BigRat "$a/$b";
return "$f";
}

关于regex - 正则表达式以匹配不可约分数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5678422/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com