使用Perl处理任意命令行选项是否有良好(理想的CPAN)方式?
例如,取一个字符串"-a 1 -b 'z -x' -c -d 3 4"
并生成一个类似GetOpt::Long
的数据结构:
{ a=>1, b=>"z -x", c=>1, d=>[3,4] } # d=>"3 4" is acceptable
需要注意的是
预先不知道这组选项;所以我们似乎无法按原样使用GetOpt::Long
。
值本身可以包含其他选项,因此简单地解析#\b+-(\S+)\b#
模式的字符串以查找THAT字符串中的所有选项似乎也是不可能的,并且一些参数的变得更复杂= s类型,some = s @,某些“-xabc”类型。
此外,即使我们可以做#2,GetOptionsFromString
是否也支持正确的引用值的引用值?
注意:假设练习的目的是所有参数都是“选项”,换句话说,如果你将字符串拆分成(可能是引用的)标记,你的结构总是
"-opt1 arg1a [arg1b] -opt2 ....".
换句话说,任何以短划线开头的单词/标记都是一个新选项,所有不以短划线开头的后续单词/标记都是该选项的值。
答案 0 :(得分:4)
使用Text :: Parsewords和简单状态机的快速示例。
#!/usr/bin/env perl
use strict;
use warnings;
use Text::ParseWords qw/shellwords/;
my $str = q{-a 1 -b 'z -x' -c -d 3 4};
my $data = parse($str);
use Data::Printer;
p $data;
sub parse {
my $str = shift;
my @tokens = shellwords $str;
my %data;
my @keys;
my $key = '_unknown';
foreach my $token (@tokens) {
if ($token =~ s/^\-//) {
$key = $token;
push @keys, $key;
next;
}
if ( ref $data{$key} ) {
push @{ $data{$key} }, $token;
} elsif (defined $data{$key}) {
$data{$key} = [ $data{$key}, $token ];
} else {
$data{$key} = $token;
}
}
foreach my $key (@keys) {
next if defined $data{$key};
$data{$key} = 1;
}
return \%data;
}
答案 1 :(得分:1)
在我了解Getopt::Long
以及使用它的智慧之前,我推出了自己的命令行选项处理器,它将采用任意参数并填充全局哈希表。规则是
用单个字母切换(-A .. -Z,-a .. -z)
-n sets $args{"n"} = 1
-nfoo sets $args{"n"} = "foo"
切换多个字母
--foo sets $args{"foo"} = 1
--foo=bar sets $args{"foo"} = "bar"
这种方法的喜悦和伤害是您可以快速尝试新的命令行选项,在使用该选项时更改代码而无需编辑对GetOptions
的调用或必须分配另一个变量:
... line 980 ...
if ($args{"do-experimental-thing"}) {
# new code
do_experimental_thing();
} else {
do_normal_thing();
}
这是我上传到CPAN的第一个模块,我已将其删除,但BackPAN内存很长。