Kelimeler Maç için hızlı PHP Rutin

6 Cevap php

Bir anahtar kelime listesi almak ve all words için (başlıklar bir dizi gibi) bir arama sonucu için maç PHP en hızlı yolu nedir?

Örneğin, benim kelime öbeği "great leather shoes" ise, o zaman aşağıdaki başlıklar would be bir maç ...

  • Get Bazı Gerçekten Great Leather Shoes
  • Leather ShoesGreat
  • Great Day! Bu Bazı Cool mısınız Leather Shoes!
  • Shoes, Leather, Olabilir Great yapılmıştır

... Bu would not be, bir maç sırasında:

  • Leather Shoes Satış Bugün!
  • Sen Leather Shoes büyük ölçüde Bu Seveceğim
  • Great Shoes ucuz gelmiyor

Ben hızla bu başarmak için dizi işlevler veya bir RegEx'in ile bazı hile (Düzenli İfade) var hayal.

6 Cevap

Ben başlıklarında sözcükler için bir dizin kullanmak ve her arama terimi o endeksinde ise bir test olacağını:

$terms = explode(' ', 'great leather shoes');
$titles = array(
    'Get Some Really Great Leather Shoes',
    'Leather Shoes Are Great',
    'Great Day! Those Are Some Cool Leather Shoes!',
    'Shoes, Made of Leather, Can Be Great'
);
foreach ($titles as $title) {
    // extract words in lowercase and use them as key for the word index
    $wordIndex = array_flip(preg_split('/\P{L}+/u', mb_strtolower($title), -1, PREG_SPLIT_NO_EMPTY));
    // look up if every search term is in the index
    foreach ($terms as $term) {
        if (!isset($wordIndex[$term])) {
            // if one is missing, continue with the outer foreach
            continue 2;
        }
    }
    // echo matched title
    echo "match: $title";
}

Eğer böyle bir şeye karşı) (dizinizi preg_grep edebilirsiniz

 /^(?=.*?\bgreat)(?=.*?\bleather)(?=.*?\shoes)/

ya da (muhtemelen daha hızlı) ayrı ayrı her kelime grep ve ardından sonuçları array_intersect

Bu oldukça naif bir çözüm (büyük olasılıkla daha verimli / zarif çözümler vardır) olabilir, ama I'ld muhtemelen aşağıdaki gibi bir şey yapın:

$keywords = array(
    'great',
    'leather',
    'shoes'
);

$titles = array(
    'Get Some Really Great Leather Shoes',
    'Leather Shoes Are Great',
    'Great Day! Those Are Some Cool Leather Shoes!',
    'Shoes, Made of Leather, Can Be Great',
    'Leather Shoes on Sale Today!',
    'You\'ll Love These Leather Shoes Greatly',
    'Great Shoes Don\'t Come Cheap'
);

$matches = array();
foreach( $titles as $title )
{
  $wordsInTitle = preg_split( '~\b(\W+\b)?~', $title, null, PREG_SPLIT_NO_EMPTY );
  if( array_uintersect( $keywords, $wordsInTitle, 'strcasecmp' ) == $keywords )
  {
    // we have a match
    $matches[] = $title;
  }
}

var_dump( $matches );

Bu olsa benchmark nasıl hiçbir fikrim yok.

Sen kullanabilirsiniz

/(?=.*?\great\b)(?=.*?\bshoes\b)(?=.*?\bleather\b)/

Bir kaç şey Not

a) hem de kelime sınırları gerekir Eğer "Büyüklüğünü getirmek deri ayakkabı" örneğin arıyoruz olanları içeren sözcükleri eşleşen bitebileceğini başka biter.

b) Ben tembel joker maç (yani kullanabilir. *?). (O maç gibi yani o kadar çok karakter tüketir, ve sadece bir genel maçında lehine onları verir) açgözlü varsayılan * ile bu, kullanılarak verimlilik geliştirir. Biz sondaki yoksa? Yani,. * Hattında her şeyi karşılayan ve daha sonra 'büyük' ​​maç sarfınazar edecek. Aynı prosedür, ayakkabı 've' deri 'için tekrarlanır. * Tembel yaparak, biz bu gereksiz Backtracks kaçının.

Ben absolute en hızlı yolu hakkında bilmiyorum, ama bu muhtemelen bir regex ile bunu yapmak için en hızlı yolu:

'#(?:\b(?>great\b()|leather\b()|shoes\b()|\w++\b)\W*+)++\1\2\3#i'

Bu dize her sözcüğü maçlar ve kelime anahtar kelimeleriniz biri olmak olur, boş yakalama grubu "kapalı denetler". Dize tüm kelimeler eşleştirilir edildikten sonra, geri-referanslı (\1\2\3), üç anahtar kelimelerin her biri en az bir kez görülmüştür emin olun.

Kez her bir anahtar kelime için - genellikle görevin bu tür tavsiye lookahead-tabanlı yaklaşım, tüm dize potansiyel birden çok kez taramak gerekiyor. Bu regex sadece bir kez dize tarama vardır - aslında, yararlar iyelik nicelik (++, *+) ve atomik gruplar tarafından devre dışı bırakılır ((?>...)) .

Ben bir tıkanıklık neden bunu biliyordu sürece söyledi, ben hala ileri yönlü yaklaşımı ile gitmek istiyorum. Çoğu durumda, kendi yüksek okunabilirlik performans ticari-off değerdir.

Sana kesin bir cevap vermiyoruz ama önerilir her çözüm kıyaslama denemek istiyorum ve birlikte bazı in_array 's zincirleme ile başlamak istiyorum.

if (in_array('great', $list) && in_array('leather', $list) && in_array('shoes', $list)) {
    // Do something
}