一致するグループを使用して完全修飾パスのディレクトリとファイル名を解析する正規表現を作成しようとしています。
そう...
/var/log/xyz/10032008.log
group 1 to be "/var/log/xyz"
およびgroup 2 to be "10032008.log"
簡単に思えますが、私は一致するグループを私の人生のために働かせることはできません。
注:一部の回答者が指摘したように、これはおそらく正規表現の適切な使用ではありません。一般的に、使用している言語のファイルAPIを使用することを好みます。私が実際にやろうとしているのはこれよりも少し複雑ですが、説明するのははるかに困難だったので、根本的な問題を最も簡潔に記述するために誰もが精通しているドメインを選択しました。
これを試して:
^(.+)/([^/]+)$
非キャプチャグループ の正規表現をサポートする言語では:
((?:[^/]*/)*)(.*)
危険な正規表現を爆発させて説明します...
(
(?:
[^/]*
/
)
*
)
(.*)
各部の意味:
( -- capture group 1 starts
(?: -- non-capturing group starts
[^/]* -- greedily match as many non-directory separators as possible
/ -- match a single directory-separator character
) -- non-capturing group ends
* -- repeat the non-capturing group zero-or-more times
) -- capture group 1 ends
(.*) -- capture all remaining characters in group 2
正規表現をテストするために、次のPerlスクリプトを使用しました...
#!/usr/bin/Perl -w
use strict;
use warnings;
sub test {
my $str = shift;
my $testname = shift;
$str =~ m#((?:[^/]*/)*)(.*)#;
print "$str -- $testname\n";
print " 1: $1\n";
print " 2: $2\n\n";
}
test('/var/log/xyz/10032008.log', 'absolute path');
test('var/log/xyz/10032008.log', 'relative path');
test('10032008.log', 'filename-only');
test('/10032008.log', 'file directly under root');
スクリプトの出力...
/var/log/xyz/10032008.log -- absolute path
1: /var/log/xyz/
2: 10032008.log
var/log/xyz/10032008.log -- relative path
1: var/log/xyz/
2: 10032008.log
10032008.log -- filename-only
1:
2: 10032008.log
/10032008.log -- file directly under root
1: /
2: 10032008.log
ほとんどの言語には、これを既に提供するパス解析関数があります。能力がある場合は、すぐに使用できるものを無料で使用することをお勧めします。
/がパス区切り文字であると仮定...
^(.*/)([^/]*)$
最初のグループはディレクトリ/パス情報が何であれ、2番目はファイル名になります。例えば:
何語?そして、なぜこの単純なタスクに正規表現を使用しますか?
mustの場合:
^(.*)/([^/]*)$
必要な2つの部分を提供します。括弧を引用する必要がある場合があります。
^\(.*\)/\([^/]*\)$
好みの言語構文に応じて。
しかし、最後の「/」文字を見つける言語の文字列検索機能を使用し、そのインデックスで文字列を分割することをお勧めします。
これはどうですか?
[/]{0,1}([^/]+[/])*([^/]*)
確定的:
((/)|())([^/]+/)*([^/]*)
厳しい:
^[/]{0,1}([^/]+[/])*([^/]*)$
^((/)|())([^/]+/)*([^/]*)$
私は試行錯誤の方法で少し研究しました。キーボードで使用可能なすべての値は、* nuxマシンの「/」を除くファイルまたはディレクトリとして適格であることがわかりました。
Touchコマンドを使用して、次の文字のファイルを作成し、ファイルを作成しました。
(以下のコンマ区切り値)
'!'、 '@'、 '#'、 '$'、 "'"、'% '、' ^ '、' '、' * '、'( '、') '、' ' 、 '"'、 '\'、 '-'、 '、'、 '['、 ']'、 '{'、 '}'、 '`'、 '〜'、 '>'、 '<'、 ' = '、' + '、'; '、': '、' | '
「/」(ルートディレクトリであるため)とファイルコンテナ/
を作成しようとしたときにのみ失敗しました。
そして、.
を実行したときに、現在のディレクトリtouch .
の変更時刻を変更しました。ただし、file.logは可能です。
そしてもちろん、a-z
、A-Z
、0-9
、-
(ハイペン)、_
(アンダースコア)は機能するはずです。
そのため、上記の理由から、ファイル名またはディレクトリ名には/
スラッシュ以外のものを含めることができます。したがって、正規表現は、ファイル名/ディレクトリ名に存在しないものから派生します。
/(?:(?P<dir>(?:[/]?)(?:[^\/]+/)+)(?P<filename>[^/]+))/
root
ディレクトリから開始するディレクトリは、絶対パスの場合は/
で始まり、相対パスの場合はディレクトリ名で始まります。したがって、0回または1回発生する/
を探してください。
/(?P<filepath>(?P<root>[/]?)(?P<rest_of_the_path>.+))/
次に、ディレクトリとその子は常に/
で区切られます。また、ディレクトリ名には、/
以外の任意の名前を使用できます。最初に/ var /を照合しましょう。
/(?P<filepath>(?P<first_directory>(?P<root>[/]?)[^\/]+/)(?P<rest_of_the_path>.+))/
次に、すべてのディレクトリを一致させましょう
/(?P<filepath>(?P<dir>(?P<root>[/]?)(?P<single_dir>[^\/]+/)+)(?P<rest_of_the_path>.+))/
ここで、single_dirはyz/
です。最初にvar/
に一致し、次に同じパターンの次の出現、つまりlog/
を見つけ、次に同じパターンの次の出現yz/
を見つけたからです。したがって、最後に出現したパターンを示しました。
これで、single_dir、filepath、rootなどのグループを決して使用しないことがわかります。したがって、それをクリーンアップしましょう。
それらをグループとして保持しますが、それらのグループをキャプチャしません。
そして、rest_of_the_pathは単なるファイル名です!そのため、名前を変更します。また、ファイルの名前には/
が含まれないため、[^/]
を保持することをお勧めします
/(?:(?P<dir>(?:[/]?)(?:[^\/]+/)+)(?P<filename>[^/]+))/
これにより、最終結果が得られます。もちろん、他にもいくつかの方法があります。私はここで方法の1つに言及しています。
^
は、文字列が次で始まることを意味します(?P<dir>pattern)
は、グループ名でグループをキャプチャすることを意味します。グループ名がdir
とfile
の2つのグループがあります(?:pattern)
は、このグループまたは非キャプチャグループを考慮しないことを意味します。?
は、0または1に一致することを意味します。 +
は1つ以上の[^\/]
と一致することを意味し、スラッシュ(/
)以外の任意の文字と一致することを意味します
[/]?
は、絶対パスの場合は/で開始できることを意味し、そうでない場合は開始しません。したがって、/
のゼロまたは1回の出現に一致します。
[^\/]+/
は、スラッシュではない1つ以上の文字(/
)の後にスラッシュ(/
)が続くことを意味します。これは、var/
またはxyz/
と一致します。一度に1つのディレクトリ。
これを試して:
/^(\/([^/]+\/)*)(.*)$/
ただし、パスには末尾のスラッシュが残ります。
非常に遅い答えですが、これが役立つことを願っています
^(.+?)/([\w]+\.log)$
これは/
の遅延チェックを使用し、受け入れられた答えを修正しました