他の答えが見逃している非常に重要な部分は、その行が
grep {s/(\d+)/sprintf"%06.6d",$1/ge,1} @_;
関数に渡された引数を実際に変更しているのであって、それらのコピーではありません。
grep
はフィルタリングコマンドであり$_
、コードブロック内の値はの値の1つのエイリアスです@_
。 @_
次に、関数に渡された引数のエイリアスが含まれているため、s///
演算子がその置換を実行すると、元の引数に変更が加えられます。これを次の例に示します。
sub test {grep {s/a/b/g; 1} @_}
my @array = qw(cat bat sat);
my @new = test @array;
say "@new"; # prints "cbt bbt sbt" as it should
say "@array"; # prints "cbt bbt sbt" as well, which is probably an error
探している動作(リストのコピーに変更する関数を適用する)は、関数としていくつかのモジュールに$_
カプセル化されています。apply
私のモジュールList::Genには、そのような実装が含まれています。 apply
自分で書くのもかなり簡単です。
sub apply (&@) {
my ($sub, @ret) = @_;
$sub->() for @ret;
wantarray ? @ret : pop @ret
}
これで、コードは次のように書き直すことができます。
sub natural_sort {
apply {s/(^|\D)0+(\d)/$1$2/g} sort apply {s/(\d+)/sprintf"%06.6d",$1/ge} @_
}
繰り返し置換を行う目的が、一時的な変更を適用して元のデータの一種を実行することである場合は、その目標を達成するためのより効率的な方法であるシュワルツ変換と呼ばれるPerlイディオムを調べる必要があります。