2

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

警告はそれです

  1. オプションのセットは事前にはわかりません。そのため、そのままでは使用できないようGetOpt::Longです。

  2. 値自体に他のオプションを含めることができるため、#\b+-(\S+)\b#パターンの文字列を解析してその文字列内のすべてのオプションを見つけることも不可能であるように思われ、一部のパラメータが= sタイプ、一部= s @、一部" -xabc"タイプ。

  3. さらに、#2を実行できたとしても、GetOptionsFromString引用符で囲まれた値を尊重する正しいトークン化をサポートしていますか?


注:演習の目的で、すべての引数が「オプション」であると想定します。つまり、文字列を(引用符で囲まれた)トークンに分割すると、構造は常に

 "-opt1 arg1a [arg1b] -opt2 ....".

つまり、ダッシュで始まる単語/トークンはすべて新しいオプションであり、ダッシュで始まらない後続のすべての単語/トークンはそのオプションの値です。

4

2 に答える 2

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;
}
于 2012-11-28T20:47:07.677 に答える
1

それを知り、それを使用する知恵を知る前にGetopt::Long、任意の引数を取り、グローバル ハッシュテーブルにデータを入力する独自のコマンド ライン オプション プロセッサを展開しました。ルールは

1 文字で切り替えます (-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には長い記憶があります。

于 2012-11-28T20:46:34.150 に答える