كيف يمكنك إجراء preg_match حيث يكون النمط عبارة عن مصفوفة في PHP؟

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

  •  22-08-2019
  •  | 
  •  

سؤال

لدي مجموعة كاملة من الأنماط التي أحتاج إلى مطابقتها.هل هناك أي طريقة للقيام بذلك بخلاف حلقة for()؟أحاول القيام بذلك بأقل طريقة مكثفة لوحدة المعالجة المركزية، لأنني سأقوم بالعشرات من هذه الأشياء كل دقيقة.

المثال الواقعي هو أنني أقوم بإنشاء مدقق حالة الرابط، والذي سيفحص الروابط إلى مواقع الفيديو المختلفة عبر الإنترنت، للتأكد من أن مقاطع الفيديو لا تزال حية.يحتوي كل مجال على عدة "كلمات رئيسية ميتة"، إذا تم العثور عليها في ملف HTML الخاص بالصفحة، فهذا يعني أنه تم حذف الملف.يتم تخزين هذه في المصفوفة.أحتاج إلى مطابقة محتويات المصفوفة مع مخرجات html للصفحة.

هل كانت مفيدة؟

المحلول

بادئ ذي بدء، إذا كنت تفعل حرفيا فقط العشرات كل دقيقة, ، فلن أقلق بشدة بشأن الأداء في هذه الحالة.هذه المطابقات سريعة جدًا، ولا أعتقد أنك ستواجه مشكلة في الأداء من خلال التكرار عبر مصفوفة الأنماط الخاصة بك واستدعاء preg_match بشكل منفصل مثل هذا:

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

يمكنك بالفعل دمج جميع الأنماط في نمط واحد باستخدام 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 في كل مرة.

إذا كان لديك مجموعة من الأنماط، ما يمكنك القيام به هو سلسلة لهم في التعبير العادي واحد وتطابق ذلك. لا حاجة للحلقة.

وماذا عن القيام str_replace() على HTML تحصل باستخدام مجموعة الخاصة بك ومن ثم التحقق إذا كان HTML الأصلية تساوي الأصلي؟ وهذا سيكون سريع جدا:

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

ويمكنك الجمع بين جميع أنماط من القائمة لتعبير عادي واحد باستخدام تنهار () وظيفة بي. ثم اختبار سلسلة الخاص بك في آن واحد باستخدام preg_match () فب ظيفة.

$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
}

وبالطبع يمكن أن يكون هناك قانون حتى أقل باستخدام تنهار () مضمنة في "إذا ()" حالة بدلا من متغير $master_pattern.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top