0

文字列から 4 つのチャンクの情報を抽出しようとしています。文字列は、拡張子を含むファイルの名前です。最初のグループには、2 番目のグループの前のスペースに達するまで、任意の有効な文字を含めることができます。2 番目のデータ グループは、一連の角括弧内に含まれる 4 つの数値です。そのグループは、最初のグループとスペースで区切られています。3 番目のグループは、3 つまたは 4 つの数字の後に文字「p」が続きます。このグループも、前のグループとはスペースで区切られています。最後のグループは単なるファイル拡張子です。

次に例を示します。

This, could be ['a'] s(@m)pl3 file name_with any characters [1923] (720p).avi

次に、次のように解析する必要があります。

$1 = This, could be ['a'] s(@m)pl3 file name_with any characters
$2 = 1923
$3 = 720p
$4 = avi
4

5 に答える 5

3

perldocperlrerefも参照してください。

サンプル文字列を考慮に入れるための更新された例を次に示します。

#!/usr/bin/env perl

use strict; use warnings;

my $x = q{This, could be ['a'] s(@m)pl3 file name_with any characters [1923] (720p).avi};

my $pat = qr{
    \A
    (.+?)
    [ ]
    \[ ( [0-9]{4} ) \]
    [ ]
    \( ( [0-9]+ p ) \)
    [.]
    (.+)
    \z
}x;

print "---$_---\n" for $x =~ $pat;

出力:

---これは、['a'] s(@m)pl3ファイル名_任意の文字である可能性があります---
---1923 ---
--- 720p ---
--- avi ---
于 2012-05-01T12:39:03.963 に答える
3

Perl であろうとなかろうと、正規表現の問題は、その欲張りさにある場合があります。誰かの名をキャプチャしたいとしましょう。文字列は次のようになります。

Bob Baker

次の正規表現を使用できます。

sed 's/^\(.*)\ .*$/\1/'

これはBob Bakerでは機能しますが、 Bob Barry Bakerでは機能しません。問題は、私の正規表現が貪欲で、最後のスペースまでのすべての文字を選択することです。これを解決する一般的な方法は、不要な文字を除くすべての文字を指定することです。BobBob Baker

sed 's/^\([^ ]*)\ .*$/\1/'

この場合、スペースを含まない任意の文字セットを指定しています。これにより、Bob Bakerとの両方が に変更Bob Rudolph BakerされますBob

Perl には、非貪欲な正規表現を指定する別の方法があります。?Perl では、貪欲にならないようにする部分式にa を追加します。上記の例では、これらはどちらも次を含む文字列を次のように変更しBob Barry BakerますBob

$string =~ s/^([^ ]+) .*$/$1/;
$string =~ s/^(.+?) .*$/$1/;

ちなみに、これらは等価ではありません!

スペース正規表現以外のすべてを使用すると、次のことができます。

 $string =~ /^([^ ]+)( )(\[\d{4}\])( )(\(\d+p\))(\.)([^.]+)/

貪欲でない修飾子を使用すると、次のようになります。

$string =~ /^(.+?)( )(\[\d{4}\])( )(\(\d+p\))(\.)(.*)/

また、x修飾子を使用すると、同じ正規表現を複数行に渡って配置できます。コメントを追加して、何をしているのかを説明できるので便利です。

$string =~ /
     ^(.+?)                   #Any set of characters (non-greedy)
     ([ ])                    #Space
     (\[\d{4}\])              #[1959]
     ([ ])                    #Space
     (\([0-9]+p\))            #(430p)
     [.]                      #Period
     ([^\.]+)                 #File Suffix (no period)
/x

そして、この時点で、Damian Conway のPerl 正規表現に関するベスト プラクティスの推奨事項に従うこともできます。

$string =~ /
     \A                 #Start of Regular Expression Anchor
     ( .+? )            #Any set of characters (non-greedy)
     ( [ ] )            #Space
     ( \[ \d{4} \] )    #[1959]
     ( [ ] )            #Space
     ( \( [0-9] +p \) ) #(430p)
     ( [.] )            #Period
     ( [^\.]+ )         #File Suffix (no period)
     \Z                 #End of string anchor
/xm;

すべてxの空白を無視するため、同じ行のサブグループ間にスペースを追加することもできます。この場合、は よりも少しクリーンです。理解しやすいかどうかは、あなた次第です。( .*+? )(.*+?)( \( [0-9] +p \) )( \( [0-9]+p \) )( \([0-9]+p\) )

そして、はい、答えはシナンの答えに非常によく似ています。

ちなみに、シナンが示したように、貪欲でない正規表現修飾子a b c d e [1234] (1080p).movを使用すると解析できますが、スペース部分式を含まないものはすべて使用できません。だから、私はそれらが同じではないと言いました。

于 2012-05-01T16:21:21.163 に答える
1

私はこのように正規表現を書きます(.*?) (\[\d{4}\]) (\(\d+p\))\.(.*)

テストしていませんが、もっとうまく書くことができます:)

于 2012-05-01T12:45:21.887 に答える
0

私は Perl を使用していないため、正規表現を微調整する必要があるかもしれませんが、私の知る限り:

(any set of characters) = \S*
(a space) = \s+
('[' + 4 numbers + ']') = \[[0-9]{4}
(a space) = \s+
('(' + an unknown number of numbers + 'p)') = \([0-9]+p\)
(a period) = \.
(file extension)  = .{2,5}
于 2012-05-01T12:45:22.480 に答える
0

これは、ファイル名を解析しようとしているようです。シナンが正しく推測した場合、次のようになります。

$x = 'a b c d e [1234] (1080p).mov'

ここで、これを解析する正規表現を作成できますが、さまざまな文字と複雑な正規表現を使用すると、維持するのが難しく、壊れやすい場合があります。では、より簡単に使用してみませんsplitか?

my @fields = split ' ', $x; 

単一のスペースで分割することもできます/ /が、どこかに複数のスペースがある場合、複数の空のフィールドのリスクがあります。また、改行は削除されません。

もちろん、それはあなたがどのフィールドをキャプチャしたいかによって異なりますが、あなたがそれについて言及していないので、私はあなたを助けることができません. 後で配列も解析できることに注意してください。

my @nums  = grep /\d/, @fields;       # anything with numbers
my ($tag) = grep /\[\d+\]/, @fields;  # catch first [1234] type field

要点は、正規表現の作成と保守が容易になったことです。

文字列の末尾から逆方向に一致を行うことに依存している場合は、reverse関数を と組み合わせて使用​​できます。次にsplit例を示します。

my $xrev   = reverse $x;
my @fields = split ' ', $xrev, 3; 

「3」は作成されるフィールド数の制限であるため、@fields現在は 3 つの文字列のみが含まれています。

于 2012-05-01T15:29:04.877 に答える