1

私はphpで使用している正規表現を持っています:

$word_array = preg_split(
    '/(\/|\.|-|_|=|\?|\&|html|shtml|www|php|cgi|htm|aspx|asp|index|com|net|org|%|\+)/',
    urldecode($path), NULL, PREG_SPLIT_NO_EMPTY
);

それはうまくいきます。次のような URL パラメーターのチャンクが必要です。

/2009/06/pagerank-update.html

次のような配列を返します。

array(4) {
  [0]=>
  string(4) "2009"
  [1]=>
  string(2) "06"
  [2]=>
  string(8) "pagerank"
  [3]=>
  string(6) "update"
}

私が必要とする唯一のことは、3 文字未満の文字列も返さないことです。したがって、"06"文字列はガベージであり、現在、if ステートメントを使用してそれらを除外しています。

4

5 に答える 5

4

分割の魔法。私の最初の仮定は技術的に正しくありませんでした (解決策は簡単に得られますが)。それでは、分割パターンを確認しましょう。

(\/|\.|-|_|=|\?|\&|html|shtml|www|php|cgi|htm|aspx|asp|index|com|net|org|%|\+)

ちょっとアレンジし直しました。外側の括弧は必要ありません。最後に、単一の文字を文字クラスに移動しました。

 html|shtml|www|php|cgi|htm|aspx|asp|index|com|net|org|[\/._=?&%+-]

それは、事前にソートするためのものです。sこのパターンを分割パターンと呼び、定義しましょう。

split-at パターンのこれらの文字以外のすべての部分と、少なくとも 3 文字を一致させる必要があります。

正しい分割シーケンスのサポートと Unicode サポートを含む、次のパターンでこれを実現できました。

$pattern    = '/
    (?(DEFINE)
        (?<s> # define subpattern which is the split pattern
            html|shtml|www|php|cgi|htm|aspx|asp|index|com|net|org|
            [\\/._=?&%+-] # a little bit optimized with a character class
        )
    )
    (?:(?&s))          # consume the subpattern (URL starts with \/)
    \K                 # capture starts here
    (?:(?!(?&s)).){3,} # ensure this is not the skip pattern, take 3 characters minimum
/ux';

または小さい:

$path       = '/2009/06/pagerank-update.htmltesthtmltest%C3%A4shtml';
$subject    = urldecode($path);
$pattern    = '/(?(DEFINE)(?<s>html|shtml|www|php|cgi|htm|aspx|asp|index|com|net|org|[\\/._=?&%+-]))(?:(?&s))\K(?:(?!(?&s)).){3,}/u';
$word_array = preg_match_all($pattern, $subject, $m) ? $m[0] : [];
print_r($word_array);

結果:

Array
(
    [0] => 2009
    [1] => pagerank
    [2] => update
    [3] => test
    [4] => testä
)

同じ原理を使用することもできますpreg_split。少し違います:

$pattern = '/
    (?(DEFINE)       # define subpattern which is the split pattern
        (?<s>
    html|shtml|www|php|cgi|htm|aspx|asp|index|com|net|org|
    [\/._=?&%+-]
        )
    )
    (?:(?!(?&s)).){3,}(*SKIP)(*FAIL)       # three or more is okay
    |(?:(?!(?&s)).){1,2}(*SKIP)(*ACCEPT)   # two or one is none
    |(?&s)                                 # split @ split, at least
/ux';

使用法:

$word_array = preg_split($pattern, $subject, 0, PREG_SPLIT_NO_EMPTY);

結果:

Array
(
    [0] => 2009
    [1] => pagerank
    [2] => update
    [3] => test
    [4] => testä
)

これらのルーチンは要求どおりに機能します。しかし、これにはパフォーマンスと価格があります。コストは古い回答と同様です。

関連する質問:


古い答え、2段階の処理を行う(最初の分割、次にフィルタリング)

分割ルーチンを使用しているため、長さに関係なく分割されます。

したがって、できることは、結果をフィルタリングすることです。正規表現 ( preg_filter) を使用して、これをもう一度行うことができます。たとえば、小さい 3 文字をすべて削除するものです。

$word_array = preg_filter(
    '/^.{3,}$/', '$0', 
    preg_split(
        '/(\/|\.|-|_|=|\?|\&|html|shtml|www|php|cgi|htm|aspx|asp|index|com|net|org|%|\+)/',
        urldecode($path), 
        NULL, 
        PREG_SPLIT_NO_EMPTY
    )
);

結果:

Array
(
    [0] => 2009
    [2] => pagerank
    [3] => update
)
于 2012-12-21T17:36:20.667 に答える
1

preg_match()代わりに試してみてはpreg_split()どうですか?

パターン (アサーションを使用):

/([a-z0-9]{3,})(?<!htm|html|shtml|www|php|cgi|htm|aspx|asp|index|com|net|org)/iu

関数呼び出し:

$pattern = '/([a-z0-9]{3,})(?<!htm|html|shtml|www|php|cgi|htm|aspx|asp|index|com|net|org)/iu';
$subject = '/2009/06/pagerank-update.html';
preg_match_all($pattern, $subject, $matches);
print_r($matches);

ここで関数を試すことができます: functions-online.com/preg_match_all.html

お役に立てれば

于 2012-12-21T17:56:37.690 に答える
1

URL から意味を導き出そうとしているのであれば、値を導き出すために複雑な正規表現を必要としないような方法で実際にクリーンな URL を書きたいと思うでしょう。

多くの場合、これにはサーバー リダイレクト ルールとフロント コントローラーまたはリクエスト ルーターの使用が含まれます。

あなたが構築するものはきれいなURLのようなものです

/value1/value2/value3

URL に 、 などは.htmlまったくありません。.php

システム (つまり Web サーバー) に入る時点で問題に適切に対処していないように思えます。

于 2012-12-21T17:38:25.197 に答える
1

ある種の URL ルーターを構築していると思います。

どのパラメーターが有用でどれが有用でないかを検出することは、このコードの一部であってはなりません。短いパラメータが関連しているかどうかは、ページごとに異なる場合があります。

この場合、1 番目の要素を無視することはできませんか? あなたのページ (または「ハンドラー」) は、呼び出したいパラメーターについての知識を持っている必要があり、トリアージを行う必要があります。

于 2012-12-21T17:31:50.403 に答える