2

私のマインドブレイカーを見てください。

私は次のように、正規表現でいくつかの長いパスを縮小することに固執していました:

/12345/123456/1234/123/12/1/1234567/13245678/123456789/1234567890

このパスを次の形式に変換したいと思います。

/123/123/123/123/12/1/123/123/123/123

パス内の各「ディレクトリ」は、最初の3文字のみを省略します

LONG_PATH="/12345/123456/1234/123/12/1/1234567/13245678/123456789/1234567890"
perl -pe "s#/(.{1,3})[^/]*?(/|$)#/\1\2#g" <<<$LONG_PATH

/ 123/123456/123/123/12 // 1234567/132/123456789/123

sed -E "s#/(.{1,3})[^/]*?(/|$)#/\1\2#g" <<<$LONG_PATH

/ 123/123456/123/123/12 // 1234567/132/123456789/123

私も試しました:

perl -pe "s,/(.)(.)?(.)?[^/]*+,/\1\2\3,g" <<<$LONG_PATH
/123/123/123/123/12//123/132/123/123

そして他の多くの、「運」はありません-私はまだ知りません。

成功への正しい道を教えてください。

4

3 に答える 3

7

最大3つの非スラッシュ文字を一致させ、それらをキャプチャします。次に、次のスラッシュまで残りを一致させます。キャプチャに置き換えます:

"s#(/[^/]{3})[^/]*#\1#g"

/否定された文字クラスはorと相互に排他的であるため、ここでは貪欲さなどは必要ありません$

編集:あなたはこれを知っているようですが、私はおそらく将来の訪問者のために、これがどちらかで、またはあなたがあなたの質問でそれを使用したように機能することを明確にする必要perl -pe...sed -E...あります。正規表現は、そのまま使用することもできますsed -r...-Eまたはオプションを省略した場合-rは、(通常どおり)括弧と中括弧の両方をエスケープする必要があります。

sed "s#\(/[^/]\{3\}\)[^/]*#\1#g" filename

また、ikegamiが指摘しているように、Perlでは。$1よりも置換に使用する必要があり\1ます。

于 2012-11-11T20:12:00.420 に答える
3

次のようにできます。

perl -pe's#[^/]{3}\K[^/]*##g'
/12345/123456/1234/123/12/1/1234567/13245678/123456789/1234567890
/123/123/123/123/12/1/123/132/123/123

3 つの非スラッシュを見つけて保持 ( \K) し、次のスラッシュまで次の文字を削除します。

池上が指摘したように、一致する文字が 3 文字未満である必要はありません。その場合、 の代わりに後読みアサーションを使用できます\K。利点は、\Kperl v5.10 を必要とすることであり、ルックアラウンド アサーションはそれよりも前にあると思います。

perl -pe 's#(?<=[^/]{3})[^/]*##g'
于 2012-11-11T20:42:18.140 に答える
0

最良の方法は、File::Specモジュールを使用してパスを分割および再結合するようです。の中間呼び出しmapは、各パスセグメントを最初の3文字に減らします。このプログラムは

use strict;
use warnings;

use File::Spec;

my $path = '/12345/123456/1234/123/12/1/1234567/13245678/123456789/1234567890';

my $newpath = File::Spec->catdir(map substr($_, 0, 3), File::Spec->splitdir($path));

print $newpath;

出力

/123/123/123/123/12/1/123/132/123/123
于 2012-11-12T18:22:49.503 に答える