perlre 长度限制

标签 perl regex

来自 man perlre :

The "*" quantifier is equivalent to "{0,}", the "+" quantifier to "{1,}", and the "?" quantifier to "{0,1}". n and m are limited to integral values less than a preset limit defined when perl is built. This is usually 32766 on the most common platforms. The actual limit can be seen in the error message generated by code such as this:

       $_ **= $_ , / {$_} / for 2 .. 42;


是的,这很丑 - 不是有一些我可以得到的常数吗?

编辑:正如 daxim 指出的(和 perlretut 暗示的),32767 可能是一个神奇的硬编码数字。一点searching在 Perl 代码中有很长的路要走,但我不确定如何进行下一步并实际找出默认的 reg_infty 或 REG_INFTY 实际设置的位置:
~/dev/perl-5.12.2
$ grep -ri 'reg_infty.*=' *
regexec.c:      if (max != REG_INFTY && ST.count == max)
t/re/pat.t:        $::reg_infty   = $Config {reg_infty} // 32767;
t/re/pat.t:        $::reg_infty_m = $::reg_infty - 1;
t/re/pat.t:        $::reg_infty_p = $::reg_infty + 1;
t/re/pat.t:        $::reg_infty_m = $::reg_infty_m;   # Surpress warning.

编辑 2:DVK 当然是对的:它是 define d 在编译时,并且可能只能用 REG_INFTY 覆盖.

最佳答案

总结:我可以想到 3 种方法来找到极限:经验、“匹配 Perl 测试”和“理论”。

  • 经验:
    eval {$_ **= $_ , / {$_} / for 2 .. 129};
    # To be truly portable, the above should ideally loop forever till $@ is true.
    $@ =~ /bigger than (-?\d+) /; 
    print "LIMIT: $1\n"'
    

    这似乎很明显,不需要解释。
  • 匹配 Perl 测试:

    Perl 对正则表达式进行了一系列测试,其中一些(在 pat.t 中)处理测试这个最大值。因此,您可以近似认为这些测试中计算出的最大值“足够好”并遵循测试逻辑:
    use Config;
    $reg_infty = $Config {reg_infty} // 2 ** 15 - 1; # 32767
    print "Test-based reg_infinity limit: $reg_infty\n";
    

    在测试中这是基于何处的解释在下面的详细信息中。
  • 理论:这试图复制 C 代码使用的 EXACT 逻辑来生成此值。

    这听起来更难,因为它受到两件事的影响:Perl 构建配置和一堆带有分支逻辑的 C #define 语句。我能够深入研究该逻辑,但在两个问题上停滞不前:#ifdefs 引用了一堆实际上没有在我可以找到的 Perl 代码中定义的标记 - 我不知道如何从中找出在 Perl 中,那些 define 的值是什么,以及最终的默认值(假设我是对的,而那些 #ifdef 总是以默认值结束)为 #define PERL_USHORT_MAX ((unsigned short)~(unsigned)0)(实际限制是通过从结果全1 数中删除 1 位来获得的- 详情如下)。

    我也不确定如何从 Perl 访问 short 中的字节量,无论使用哪种实现来构建 perl 可执行文件。

    因此,即使可以找到这两个问题的答案(我不确定),结果逻辑肯定会比我提供的简单的“基于经验的评估”逻辑更“丑陋”和更复杂。第一个选项。

  • 下面我将详细说明与此限制相关的各种逻辑在 Perl 代码中的位置,以及我尝试得出与 C 逻辑匹配的“理论上正确”的解决方案。

    好的,这是部分调查,您可以自己完成,因为我正在运行,或者我稍后会完成:
  • 来自 regcomp.c : vFAIL2("Quantifier in {,} bigger than %d", REG_INFTY - 1);
    因此,该限制显然取自 REG_INFTY 定义。声明在:
  • rehcomp.h :
     /* XXX fix this description.
        Impose a limit of REG_INFTY on various pattern matching operations
        to limit stack growth and to avoid "infinite" recursions.
     */
     /* The default size for REG_INFTY is I16_MAX, which is the same as
        SHORT_MAX (see perl.h).  Unfortunately I16 isn't necessarily 16 bits
        (see handy.h).  On the Cray C90, sizeof(short)==4 and hence I16_MAX is
        ((1<<31)-1), while on the Cray T90, sizeof(short)==8 and I16_MAX is
        ((1<<63)-1).  To limit stack growth to reasonable sizes, supply a
        smaller default.
             --Andy Dougherty  11 June 1998
     */
     #if SHORTSIZE > 2
     #  ifndef REG_INFTY
     #    define REG_INFTY ((1<<15)-1)
     #  endif
     #endif
     #ifndef REG_INFTY
     #  define REG_INFTY I16_MAX
     #endif
    

    请注意,SHORTSIZE 可通过 Config 覆盖 - 我将省略详细信息,但逻辑需要包括 $Config{shortsize} :)
  • 来自 handy.h(乍一看这似乎不是 Perl 源代码的一部分,所以它看起来像是一个不确定的步骤):
     #if defined(UINT8_MAX) && defined(INT16_MAX) && defined(INT32_MAX)
     #define I16_MAX INT16_MAX
     #else
     #define I16_MAX PERL_SHORT_MAX
    
  • 我根本找不到定义 INT16_MAX 任何 地方:(

    有人帮忙请!!!
  • PERL_SHORT_MAX 在 perl.h 中定义:
     #ifdef SHORT_MAX
     #  define PERL_SHORT_MAX ((short)SHORT_MAX)
     #else
     #  ifdef MAXSHORT    /* Often used in <values.h> */
     #    define PERL_SHORT_MAX ((short)MAXSHORT)
     #  else
     #    ifdef SHRT_MAX
     #      define PERL_SHORT_MAX ((short)SHRT_MAX)
     #    else
     #      define PERL_SHORT_MAX      ((short) (PERL_USHORT_MAX >> 1))
     #    endif
     #  endif
     #endif
    

    到目前为止,我找不到任何定义 SHORT_MAX、MAXSHORT 或 SHRT_MAX 的地方。所以默认的 ((short) (PERL_USHORT_MAX >> 1)) 假设现在是 :)
  • PERL_USHORT_MAX 在 perl.h 中的定义非常相似,我再次找不到 USHORT_MAX/MAXUSHORT/USHRT_MAX 的定义痕迹。

    这似乎暗示它默认设置为: #define PERL_USHORT_MAX ((unsigned short)~(unsigned)0) 。如何从 Perl 端提取该值,我不知道 - 它基本上是通过按位取反短 0 得到的数字,所以如果 unsigned short 是 16 个字节,那么 PERL_USHORT_MAX 将是 16 个,而 PERL_SHORT_MAX 将是 15 个,例如2^15-1,例如32767.
  • 此外,来自 t/re/pat.t (正则表达式测试):$::reg_infty = $Config {reg_infty} // 32767;(说明非默认编译值的存储位置)。

  • 所以,为了得到你的常数,你做:
    use Config;
    my $shortsize = $Config{shortsize} // 2;
    $c_reg_infty = (defined $Config {reg_infty}) ? $Config {reg_infty}
                                                 : ($shortsize > 2) ? 2**16-1
                                                 : get_PERL_SHORT_MAX();
    # Where get_PERL_SHORT_MAX() depends on logic for PERL_SHORT_MAX in perl.h
    # which I'm not sure how to extract into Perl with any precision
    # due to a bunch of never-seen "#define"s and unknown size of "short".
    # You can probably do fairly well by simply returning 2**8-1 if shortsize==1 
    # and 2^^16-1 otherwise.
    say "REAL reg_infinity based on C headers: $c_reg_infty";
    

    关于perlre 长度限制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4592467/

    相关文章:

    linux - GDBM文件导入导出

    perl - 很难发现 Perl 脚本中的错误

    perl - 在语法中分离 G0 和 G1 规则的问题

    javascript - 检查 JSON LIKE 字符串是否有效 - JS 正则表达式

    Perl:对象方法的返回值不触发 "if"语句

    perl - mojolicious中路线名称的目的是什么?

    ruby - cucumber 测试的步骤定义应该能够处理 "a"和 "an"[正则表达式相关]

    javascript - 正则表达式模式只有一个点并匹配整数和小数

    PHP:仅在 HTML 标记之外转义引号(正则表达式)

    javascript - "reverse"正则表达式与 JavaScript(node.js)