احصل على المزيد من الخيلات من RegexP من الأقواس

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

  •  20-09-2019
  •  | 
  •  

سؤال

حسنا، من الصعب حقا شرح اللغة الإنجليزية، لذلك سأقدم مثالا فقط.

سأقدم سلاسل بالتنسيق التالي:

key-value;key1-value;key2-...

وأنا بحاجة إلى استخراج البيانات لتكون صفيف

array('key'=>'value','key1'=>'value1', ... )

كنت أخطط لاستخدام RegoxP لتحقيق (معظم) هذه الوظيفة، وكتب هذا التعبير العادي:

/^(\w+)-([^-;]+)(?:;(\w+)-([^-;]+))*;?$/

للعمل مع preg_match وهذا الرمز:

for ($l = count($matches),$i = 1;$i<$l;$i+=2) {
    $parameters[$matches[$i]] = $matches[$i+1];
}

ومع ذلك، من الواضح أن RegoxP إرجاع فقط 4 خلفية - أولا والأخيرة أزواج القيمة الرئيسية لسلسلة الإدخال. هل هناك طريقة للتغلب على ذلك؟ أعلم أنني أستطيع استخدام Regex فقط لاختبار صحة السلسلة واستخدام PHP explode في حلقات مع نتائج مثالية، لكنني فضولي حقا سواء كان ذلك ممكنا مع تعبيرات منتظمة.

باختصار، أحتاج إلى التقاط عدد التعسفي من هذه key-value; أزواج في سلسلة عن طريق التعبيرات العادية.

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

المحلول

يمكنك استخدام Lookahead للتحقق من صحة المدخلات أثناء استخراج التطابقات:

/\G(?=(?:\w++-[^;-]++;?)++$)(\w++)-([^;-]++);?/

(?=(?:\w++-[^;-]++;?)++$) هو جزء التحقق من الصحة. إذا كانت الإدخال غير صالحة، فستفشل مطابقة فورا، ولكن لا يزال يتم تقييمه Lookahead في كل مرة يتم تطبيق regex. من أجل الحفاظ عليها (جنبا إلى جنب مع بقية Regex) في المزامنة مع أزواج القيمة الرئيسية، استخدمت \G لمذكرة كل مباراة إلى المكان حيث انتهت المباراة السابقة.

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

إذا فشل مظهر نظرة، preg_match_all() سوف تعود صفر (خطأ). إذا نجحت، فسيتم إرجاع المباريات في صفيف من الصفائف: واحد لأزواج القيمة الرئيسية الكاملة، واحدة للمفاتيح، واحدة للقيم.

نصائح أخرى

Regex أداة قوية، ولكن في بعض الأحيان، ليس أفضل نهج.

$string = "key-value;key1-value";
$s = explode(";",$string);
foreach($s as $k){
    $e = explode("-",$k);
    $array[$e[0]]=$e[1];
}
print_r($array);

يستخدم preg_match_all() في حين أن. ربما شيء مثل:

$matches = $parameters = array();
$input = 'key-value;key1-value1;key2-value2;key123-value123;';

preg_match_all("/(\w+)-([^-;]+)/", $input, $matches, PREG_SET_ORDER);

foreach ($matches as $match) {
   $parameters[$match[1]] = $match[2];
}

print_r($parameters);

تعديل:

للتحقق من الصحة أولا إذا كانت سلسلة الإدخال تتفق مع النمط، ثم استخدم فقط:

if (preg_match("/^((\w+)-([^-;]+);)+$/", $input) > 0) {
    /* do the preg_match_all stuff */
}       

Edit2: الفاصلة المنقوطة النهائية اختيارية

if (preg_match("/^(\w+-[^-;]+;)*\w+-[^-;]+$/", $input) > 0) {
    /* do the preg_match_all stuff */
}       

لا. أحدث مباريات الكتابة فوق المباريات القديمة. ربما limit حجة explode() سيكون مفيدا عند انفجار.

ماذا عن هذا الحل:

$samples = array(
    "good" => "key-value;key1-value;key2-value;key5-value;key-value;",
    "bad1" => "key-value-value;key1-value;key2-value;key5-value;key-value;",
    "bad2" => "key;key1-value;key2-value;key5-value;key-value;",
    "bad3" => "k%ey;key1-value;key2-value;key5-value;key-value;"
);

foreach($samples as $name => $value) {
    if (preg_match("/^(\w+-\w+;)+$/", $value)) {
        printf("'%s' matches\n", $name);
    } else {
        printf("'%s' not matches\n", $name);
    }
}

لا أعتقد أنك تستطيع أن تفعل كل من التحقق من الصحة واستخراج البيانات مع regexp واحد واحد، كما تحتاج المراسين (^ و $) للتحقق من الصحة و preg_match_all() للبيانات، ولكن إذا كنت تستخدم المراس preg_match_all() سيعود فقط المجموعة الأخيرة المتطابقة.

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