【问题标题】:Method returning a regex in Perl 6?在 Perl 6 中返回正则表达式的方法?
【发布时间】:2018-04-22 08:09:22
【问题描述】:

我才刚开始学习课程,所以我不了解基础知识。

我想要一个使用对象属性构造regex的方法:

class TEST {
    has Str $.str;

    method reg {
        return 
            rx/
               <<
               <[abc]> *
               $!str
               <!before foo>
              /;
    }         
}   

my $var = TEST.new(str => 'baz');
say $var.reg;

在尝试运行此程序时,我收到以下错误消息:

===SORRY!=== Error while compiling /home/evb/Desktop/p6/e.p6
Attribute $!str not available inside of a regex, since regexes are methods on Cursor.
Consider storing the attribute in a lexical, and using that in the regex.
at /home/evb/Desktop/p6/e.p6:11
------>                <!before foo>⏏<EOL>
    expecting any of:
        infix stopper

那么,正确的做法是什么?

【问题讨论】:

  • 您可能需要使用词法变量构建闭包。请参阅Method returning a regex in Perl 6? 了解更多信息
  • @HåkonHægland 谢谢。我宁愿使用EVAL。 :)
  • 如果错误信息不清楚... 正则表达式是一种方法。像上面那样声明正则表达式相当于尝试将匿名方法添加到 Match 对象。 (提及Cursor 已过时——Cursor =:= Match)。所以$!str 指的是Match 中的一个属性——但Match 没有属性。所以你得到一个编译时失败。

标签: class raku private-members


【解决方案1】:

看起来这样可行:

class TEST {
    has Str $.str;

    method reg {
        my $str = $.str;
        return 
            regex {
               <<
               <[abc]> *
               $str
               <!before foo>
               }
    }         
}   

my $var = TEST.new(str => 'baz');
say $var.reg;
say "foo" ~~ $var.reg;
say "<<abaz" ~~ $var.reg

您将返回一个anonymous regex,它可以用作实际的正则表达式,就像在最后两句中所做的那样。

【讨论】:

  • 谢谢,它有效!与正则表达式 rx// 相比,使用匿名正则表达式 regex {} 有什么优势吗?
  • 它更灵活一点,因为regex 实际上是sub。例如,您可能希望使用参数来获得它。实际上,您可以只创建一个函数并 curry 以返回具有不同参数的正则表达式。
  • 这个答案的关键点是使用了词汇别名my $str = $!str。这是因为正则表达式实际上是在游标(基本上属于正则表达式引擎的对象)上调用的 方法,因此没有可用的 self 可以解析 $!str属性。此外,属性不是闭包的一部分,因此您需要词法别名。
【解决方案2】:

Using EVAL 解决了我的问题。所以,我想知道,这种方法是否有任何缺点。

class TEST {
    has Str $.str;

    method reg {
        return
            "rx/
               <<
               <[abc]> * 
               $!str
               <!before foo>
              /".EVAL;
    }
}

my $var = TEST.new(str => 'baz');
say "abaz" ~~ $var.reg;    # abaz
say "cbazfoo" ~~ $var.reg; # Nil

【讨论】:

  • 这是一个自然的动态(运行时)解决方案。明显的潜在缺点是它是动态的,因此在运行时比编译时解决方案慢。但是,对于您的用例来说,它是否可以理解且足够快并不重要。
  • 谢谢!就我而言,没关系,它只需要产生大约 200 个这样的regexes。
  • 注:尽管EVAL 的许多用途是安全的,例如您在此解决方案中的使用,但其他人则不然,因为它们可能会给code injection 带来漏洞。幸运的是,Perl 6 的设计和指定方式使得编译器能够并且确实检测到在编译时,当EVAL 的使用以这种方式存在危险时。如果是这样,编译器将拒绝编译,除非您添加另一行告诉它继续编译。除非您愿意接受这样做的挑战/后果,否则切勿添加或接受该行 (use MONKEY-SEE-NO-EVAL;)。
猜你喜欢
  • 2018-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-22
相关资源
最近更新 更多