PHPでパターンが配列であるpreg_matchを実行するにはどうすればよいですか?

StackOverflow https://stackoverflow.com/questions/683702

  •  22-08-2019
  •  | 
  •  

質問

一致させる必要があるパターンがいっぱいの配列があります。for() ループ以外にそれを行う方法はありますか?これらを毎分何十回も実行することになるため、CPU への負荷が最も少ない方法で実行しようとしています。

実際の例として、さまざまなオンライン ビデオ サイトへのリンクをチェックして、ビデオがまだライブであることを確認するリンク ステータス チェッカーを構築しています。各ドメインにはいくつかの「無効なキーワード」があり、これらがページの HTML で見つかった場合は、ファイルが削除されたことを意味します。これらは配列に格納されます。配列の内容をページの HTML 出力と照合する必要があります。

役に立ちましたか?

解決

まず第一に、文字通りただやっているだけなら、 数十の, であれば、この場合のパフォーマンスについてはそれほど心配する必要はありません。これらの一致は非常に高速であり、次のようにパターン配列を反復処理して preg_match を個別に呼び出すことによってパフォーマンスの問題が発生することはないと思います。

$matches = false;
foreach ($pattern_array as $pattern)
{
  if (preg_match($pattern, $page))
  {
    $matches = true;
  } 
}

実際、次のコマンドを使用すると、すべてのパターンを 1 つに組み合わせることができます。 or 一部の人が提案しているような演算子を使用しますが、単純にそれらを一緒に叩きつけないでください。 |. 。あなたのパターンのいずれかが発生すると、これはひどく壊れます 含む or 演算子。

少なくとも次のように括弧を使用してパターンをグループ化することをお勧めします。

foreach ($patterns as $pattern)
{
  $grouped_patterns[] = "(" . $pattern . ")";
}
$master_pattern = implode($grouped_patterns, "|");

しかし...これが最終的に高速になるかどうかはわかりません。 何か preg_match であろうと PHP であろうと、それらをループする必要があります。推測するなら、個々のマッチはほぼ同じくらい高速で、読みやすく、維持しやすいのではないかと思います。

最後に、ここでパフォーマンスを求めているのであれば、正規表現以外の一致を単純な「文字列が含まれる」チェックに取り出すことが最も重要だと思います。チェックの一部は、ページ上に「このサイトは閉鎖されています」と表示されているかどうかを確認するなど、単純な文字列チェックである必要があると思います。

したがって、これを行うと:

foreach ($strings_to_match as $string_to_match)
{
  if (strpos($page, $string_to_match) !== false))
  {
    // etc.
    break;
  }
}
foreach ($pattern_array as $pattern)
{
  if (preg_match($pattern, $page))
  {
    // etc.
    break;
  } 
}

そしてできるだけ避ける preg_match() できる限りそれが最大の利益となるでしょう。 strpos() です 多く よりも速い preg_match().

他のヒント

// assuming you have something like this
$patterns = array('a','b','\w');

// converts the array into a regex friendly or list
$patterns_flattened = implode('|', $patterns);

if ( preg_match('/'. $patterns_flattened .'/', $string, $matches) )
{
}

// PS: that's off the top of my head, I didn't check it in a code editor
あなたのパターンは多くの空白が含まれていない場合は、

、別のオプションは、配列を避け、/x修飾子を使用することです。さて、正規表現のリストは、次のようになります:

$regex = "/
pattern1|   # search for occurences of 'pattern1'
pa..ern2|   # wildcard search for occurences of 'pa..ern2'
pat[ ]tern| # search for 'pat tern', whitespace is escaped
mypat       # Note that the last pattern does NOT have a pipe char
/x";

/x改質剤と、空白は完全に文字クラスやバックスラッシュが先行する場合を除き、無視されます。上記のようなコメントも許可されています。

この配列をループを避けるだろう。

それが高速であるとして

あなたは、単に別の文字列内の文字列の存在を探している場合は、strposを使用します。

それ以外の場合は、あなただけするpreg_matchたびに呼び出し、パターンの配列を反復処理することができます。

あなたはパターンの束を持っている場合は、

、何を行うことができ、単一の正規表現でそれらを連結し、それと一致します。ループの必要はありません。

どのようなHTMLにstr_replace()ことについて、あなたの配列を使用して、元のHTMLを元に等しいかどうかをチェックするのですか?これは非常に高速になります:

 $sites = array(
      'you_tube' => array('dead', 'moved'),
      ...
 );
 foreach ($sites as $site => $deadArray) {
     // get $html
     if ($html == str_replace($deadArray, '', $html)) { 
         // video is live
     }
 }

あなたは破()を使用して、単一の正規表現をリストからすべてのパターンを組み合わせることができますのPHP関数。その後、するpreg_match()のPHPの関数を使用して、一度にあなたの文字列をテストします。

$patterns = array(
  'abc',
  '\d+h',
  '[abc]{6,8}\-\s*[xyz]{6,8}',
);

$master_pattern = '/(' . implode($patterns, ')|(') . ')/'

if(preg_match($master_pattern, $string_to_check))
{
  //do something
}

もちろん「IF()」条件の代わりに$master_pattern変数内破()インラインを使用しても少ないコードがある可能性があります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top