0

CSVセルに正しいファイルパスが含まれているかどうかをテストするための正規表現があります。

編集CSVには、スクリプトの実行時にまだ存在しないファイルパスが一覧表示され(-eは使用できません)、ファイルパスには*、%variable%、または{$variable}を含めることができます。

my $FILENAME_REGEXP = '^(|"|""")(?:[a-zA-Z]:[\\\/])?[\\\/]{0,2}(?:(?:[\w\s\.\*-]+|\{\$\w+}|%\w+%)[\\\/]{0,2})*\1$';

CSVセルには二重引用符のラッパーが含まれる場合があり、ファイル名自体を二重引用符で囲む必要がある場合があるため、このグループ化を行いました(| "|" "")... \ 1

次に、この関数を使用します。

sub ValidateUNCPath{
    my $input = shift;
    if ($input !~ /$FILENAME_REGEXP/){
        return;
    } 
    else{
        return "This is a Valid File Path.";
    }

}

このフレーズが私の正規表現と一致するかどうかをテストしようとしています(一致しないはずです):

"""c:\my\dir\lord"

しかし、私の親愛なるPerlは、次の場合に無限ループに入ります。

ValidateUNCPath('"""c:\my\dir\lord"');

EDITは実際にこれでループします:

ValidateUNCPath('"""\aaaaaaaaa\bbbbbbb\ccccccc\Netwxn00.map"');

http://regexpal.comで、正規表現がこれらの非対称の "" "..."を二重引用符で囲んで正しくキャッチすることを確認しましたが、Perlは彼自身の心を持っていました:(

/gフラグと/oフラグも試しました

/$FILENAME_REGEXP/go

しかし、それでもハングします。私は何が欠けていますか?

4

4 に答える 4

3

まず、あなたが投稿したものは無限ループを引き起こす可能性がないので、それを取得している場合、それはコードのこの部分からのものではありません.

サブルーチンを試してみると、パスのようには見えないあらゆる種類の文字列に対して true が返されます。次に例を示します。

.....
This is a Valid File Path.
.*.*
This is a Valid File Path.
-
This is a Valid File Path.

これは、正規表現がかなり緩いためです。

^(|"|""")                  # can match the empty string
(?:[a-zA-Z]:[\\\/])?       # same, matches 0-1 times
[\\\/]{0,2}                # same, matches 0-2 times
(?:(?:[\w\s\.\*-]+|\{\$\w+}|%\w+%)[\\\/]?)+\1$  # only this is not optional

実際には最後の部分だけが一致する必要があるため、主に最初の文字クラスで、あらゆる種類の文字列を許可しています。[\w\s\.\*-]

私の個人的な意見では、自分のものに似た正規表現に頼り始めると、何か間違ったことをしているということになります。あなたが正規表現に熟練していない限り、そうでない人がそれを修正することを余儀なくされないことを願っています.

引用符を削除してみませんか?また、このパスがシステムに存在する場合、それが有効かどうかを確認するより簡単な方法があります。-e $path

于 2012-05-10T16:52:54.113 に答える
1

アップデート

編集:試行錯誤から、以下のグループ化サブ式[\w\s.*-]+がバックトラックの問題を引き起こしています

    (?:
        (?:
             [\w\s.*-]+
          |  \{\$\w+\}
          |  %\w+%
        )
        [\\\/]?
    )+

修正#1、展開されたメソッド

'
 ^
    (                          # Nothing
      |"                       # Or, "
      |"""                     # Or, """
    )
                      # Here to end, there is no provision for quotes (")
    (?:               # If there are no balanced quotes, this will fail !!
        [a-zA-Z]
        :
        [\\\/]
    )?
    [\\\/]{0,2}

    (?:
        [\w\s.*-]
      |  \{\$\w+\}
      |  %\w+%
    )+
    (?:
        [\\\/]
        (?:
            [\w\s.*-]
          |  \{\$\w+\}
          |  %\w+%
        )+
    )*
    [\\\/]?
    \1
 $
'

修正#2、独立した部分表現

'
 ^
    (                          # Nothing
      |"                       # Or, "
      |"""                     # Or, """
    )
                      # Here to end, there is no provision for quotes (")
    (?:               # If there are no balanced quotes, this will fail !!
        [a-zA-Z]
        :
        [\\\/]
    )?
    [\\\/]{0,2}

    (?>
       (?:
           (?:
                [\w\s.*-]+
             |  \{\$\w+\}
             |  %\w+%
           )
           [\\\/]?
       )+
    )
    \1
 $
'

修正#3、+数量詞を削除(または+?を追加)

'
 ^
    (                          # Nothing
      |"                       # Or, "
      |"""                     # Or, """
    )
                      # Here to end, there is no provision for quotes (")
    (?:               # If there are no balanced quotes, this will fail !!
        [a-zA-Z]
        :
        [\\\/]
    )?
    [\\\/]{0,2}

    (?:
        (?:
             [\w\s.*-] 
          |  \{\$\w+\}
          |  %\w+%
        )
        [\\\/]?
    )+
    \1
 $
'
于 2012-05-10T17:08:42.357 に答える
1

正規表現エンジンがナイーブだった場合、

('y') x 20 =~ /^.*.*.*.*.*x/

試行する必要があるため、失敗するまでに非常に長い時間がかかります

20 * 20 * 20 * 20 * 20 = 3,200,000 possible matches.

あなたのパターンは同様の構造を持っています。つまり、多くのコンポーネントが入力の広範囲の部分文字列に一致します。

現在、Perl の正規表現エンジンは高度に最適化されており、ナイーブとはほど遠いものです。上記のパターンでは、 を探すことから始まり、x非常に速く終了します。残念ながら、パターンを同様に最適化することはできません。

あなたのパターンは完全に混乱しています。何が一致すると思われるかを推測しようとするつもりはありません。正しいパターンに切り替えると、この問題は自然に解決することがわかります。

于 2012-05-10T18:34:48.243 に答える
0

sln のおかげで、これは私の固定正規表現です:

my $FILENAME_REGEXP = '^(|"|""")(?:[a-zA-Z]:[\\\/])?[\\\/]{0,2}(?:(?:[\w\s.-]++|\{\$\w+\}|%\w+%)[\\\/]{0,2})*\*?[\w.-]*\1$';

(また、ディレクトリで * char を許可せず、(最後の) ファイル名で単一の * のみを許可しました)

于 2012-05-11T00:21:10.327 に答える