我想知道如何运行这样的操作
$T = 25 C; @specs = (273.15 K,23 bar,2.0 mol/s);
并让他们编译.我不会挑剔他们的结果是什么,或者它是如何实现的.我的目标是让传统后缀单元注释的物理量表达式编译为这些单元的perl表达式.
我想我需要使用自定义解析技术,但我更喜欢使用任何现有功能或解析模块,而不仅仅是将regex过滤器应用于我的原始源.
Parse::Keyword似乎很有希望,但我看不出它是否可以解析后缀操作,并声称它已被弃用.
编辑:我想尽可能避免使用源过滤器,因为我不想为Perl的语法极端情况编写正则表达式(例如“25(J / K)”).
Perl在这里产生的错误告诉我:
perl -E "25 C" Bareword found where operator expected at -e line 1,near "25 C" (Missing operator before C?)
看起来我需要挂钩Perl在数字文字之后检测运算符的地方.
Devel::Declare可以添加后缀运算符吗?如果是这样,怎么样?
解决方法
你可以滥用重载来获得你想要的东西.
#!/usr/bin/perl use strict; use warnings; use 5.010; use Data::Dumper; use MyUnits; my $T = '25 C'; say Dumper $T; my @specs = ('273.15 K','23 bar','2.0 mol/s'); say Dumper \@specs;
正如您将看到的,您可以使用“value”和“type”属性返回对象.
MyUnits.pm看起来像这样:
package MyUnits; use strict; use warnings; use overload '""' => \&to_string; my %_const_handlers = ( q => \&string_parser,); sub string_parser { my $c = eval { __PACKAGE__->new($_[0]) }; return $_[1] if $@; return $c; } sub import { overload::constant %_const_handlers; } sub new { my $class = shift; # ->new(type => ...,value => ...) if (@_ == 4) { return bless { @_ },$class; } # ->new({ type => ...,value => ...) if (@_ == 1 and ref $_[0] eq 'HASH') { return bless $_[0],$class; } # -> new('999xxx') if (@_ == 1 and ! ref $_[0]) { my ($val,$type) = $_[0] =~ /(\d+\.?\d*)\s*(.+)/; return bless({ value => $val,type => $type,}); } } sub to_string { return "$_[0]->{value}$_[0]->{type}"; } 1;
在大多数情况下,与源过滤器相比,重载并不比派对技巧少得多.它几乎肯定会使你的程序慢得多.