2017-05-24 13 views
0

私のスクリプトはファイルパスを取り入れ、パスの最後にディレクトリを追加します。問題は、議論の末尾にスラッシュがあるかどうかには無関心であることです。だから、例えば:perl:置換を使用してパスに追加する

$ perl myscript.pl /path/to/dir 
/path/to/dir/new 
$ perl myscript.pl /path/to/dir/ 
/path/to/dir/new 

私は$path =~ s/\/?$/\/new/gを試してみましたが、スラッシュが存在する場合には、二重/newになり:

$ perl myscript.pl /path/to/dir 
/path/to/dir/new/new 
$ perl myscript.pl /path/to/dir 
/path/to/dir/new 

間違っているのですか?

答えて

1

ドロップ/g修飾子:

$path =~ s/\/?$/\/new/ 
正常に動作します


末尾に1つ追加するだけで「新規」を追加したいので、/g修飾子を使用することは意味がありません。


また、あなたは正規表現のための別の区切り文字を使用できることに注意してください。

$path =~ s{ /? $}{/new}x; 

は少し明確です。

+0

ありがとうございます。それはうまくいった。何が起こったのか説明できますか? – ewok

+1

'$'は "end of string"を消費しません。単なるアサーションです( "文字列の終わりはここにあります")。だから、 '/? 'では、あなたの正規表現は2つの位置でマッチします。最初は'/'に続いて行の終わりにマッチします。それは明確ですか? – Dada

+0

一種ですが、なぜそれが無限ループにならないのですか? – ewok

2

/gは、「グローバル」であり、複数回マッチしますので:最初の交換後

#!/usr/bin/env perl 
use strict; 
use warnings; 

#turn on debugging 
use re 'debug'; 

my $path = '/path/to/dir/'; 
$path =~ s/\/?$/\/new/g; 

print $path; 

を、正規表現エンジンは、マーカー「行の末尾を」「左」している、と一致する必要はありません。オプションの/。だから、もう一度マッチします。

例えば:

Compiling REx "/?$" 
Final program: 
    1: CURLY {0,1} (5) 
    3: EXACT </> (0) 
    5: SEOL (6) 
    6: END (0) 
floating ""$ at 0..1 (checking floating) minlen 0 
Matching REx "/?$" against "/path/to/dir/" 
Intuit: trying to determine minimum start position... 
    doing 'check' fbm scan, [0..13] gave 13 
    Found floating substr ""$ at offset 13 (rx_origin now 12)... 
    (multiline anchor test skipped) 
    try at offset... 
Intuit: Successfully guessed: match at offset 12 
    12 <path/to/dir> </>  | 1:CURLY {0,1}(5) 
            EXACT </> can match 1 times out of 1... 
    13 <path/to/dir/> <>  | 5: SEOL(6) 
    13 <path/to/dir/> <>  | 6: END(0) 
Match successful! 
Matching REx "/?$" against "" 
Intuit: trying to determine minimum start position... 
    doing 'check' fbm scan, [13..13] gave 13 
    Found floating substr ""$ at offset 13 (rx_origin now 13)... 
    (multiline anchor test skipped) 
Intuit: Successfully guessed: match at offset 13 
    13 <path/to/dir/> <>  | 1:CURLY {0,1}(5) 
            EXACT </> can match 0 times out of 1... 
    13 <path/to/dir/> <>  | 5: SEOL(6) 
    13 <path/to/dir/> <>  | 6: END(0) 
Match successful! 
Matching REx "/?$" against "" 
Intuit: trying to determine minimum start position... 
    doing 'check' fbm scan, [13..13] gave 13 
    Found floating substr ""$ at offset 13 (rx_origin now 13)... 
    (multiline anchor test skipped) 
Intuit: Successfully guessed: match at offset 13 
    13 <path/to/dir/> <>  | 1:CURLY {0,1}(5) 
            EXACT </> can match 0 times out of 1... 
    13 <path/to/dir/> <>  | 5: SEOL(6) 
    13 <path/to/dir/> <>  | 6: END(0) 

$がゼロ幅位置アンカーであるためです。一致するものがない場合は\/?となります。パターンが末尾の/まで完全に消費されたら、正規表現エンジンは(/gと言っているので)続行し、まだ末尾にあるので、ちょうど$が残っていることがわかります。それでも、それは引き続き有効なマッチです。

しかし、なぜない代わりに使用File::Spec

#!/usr/bin/env perl 
use strict; 
use warnings; 
use File::Spec; 
use Data::Dumper; 

my $path = '/path/to/dir/'; 

my @dirs = File::Spec->splitdir($path); 

print Dumper \@dirs; 

$path = File::Spec->catdir(@dirs, "new"); 
print $path; 

これを分割してパス要素を結合するためのプラットフォームに依存しない方法を提供します、そして正規表現のマッチングに依存しない - それは破ることができ、さまざまな方法を(ありますあなたが見つけたもののような)。

+0

'最初の置換後、正規表現エンジンは"行末 "マーカーを '左に'持ち、オプションの/'とマッチする必要はありません。私は従わない。置き換えた後でも引き続き一致する場合、なぜこれが無限ループにならないのでしょうか? – ewok

+0

上記を実行すると、正規表現が何をしているのかがわかります。 '$'は空の文字列( '\ /?')と同じく、幅がゼロであるからです。だから、最初の置換を実行すると、正規表現は同じ開始位置から再び試行されます。前のマッチによって '/'がすでに消費されていますが、 '$'とマッチさせるために正規表現は必要ありません。 – Sobrique

関連する問題