PHP tek bir dize içinde farklı dizelerden oluşan bir dizi aranıyor

4 Cevap php

Ben denemek ve normal bir dize sonuna eşleştirmek istediğiniz dizeleri bir dizi var. PHP bunu yapmanın en iyi yolu, emin değilim.

Ben bunu yapmaya çalışıyorum ne sorta olduğunu:

Örnek:

Girdi: abcde

Arama dizisi: er, wr, de

Maç: de

Benim ilk düşünce dizinin geçer ve giriş dizesi bulunan olup olmadığını kontrol edin sonra her dizenin sonuna "\ b" ekleyerek ve düzenli bir ifade el sanatları bir döngü yazmak oldu. Bu işe iken tüm dizi döngü sorta verimsiz görünmektedir. Ben düzenli ifadeler PHP yavaş ve yanlış yolu beni alacak bir şey uygulamak istemiyorsanız söylendi.

Benim dizideki dizelerinden biri girdi dize sonunda oluşur görmek için daha iyi bir yolu var mı?

Preg_filter () işlevi işi olabilir gibi görünüyor ama PHP 5.3 + için ve ben hala stabil 5.2.11 ile yapışmasını ediyorum.

4 Cevap

Bu basit bir şey için, bir regex gerekmez. Ya dizi üzerinde döngü ve indeks (giriş) uzunluk olup olmadığını görmek için strpos kullanın - uzunluk (testi). Arama dizideki her girdinin bir sabit uzunlukta zaman ise, aynı zamanda, o dizideki her öğe için bu karşılaştırma, giriş kapalı ucunu doğrama işleri hızlandırabilir.

Kötü genel durumda eşleşen öğe dizinin sonunda olacak gibi, tüm dizi geçiyor kaçınamaz. Dizi büyük olmadıkça Ancak, ben performansı hakkında çok fazla endişe olmaz - düşündüğünüzden çok daha hızlı olacaktır.

Düzenli ifadeyi derlemek biraz zaman alır ama ben o kadar kolay PCRE'yi kullanarak görevden olmaz. Sen de zaman alır iğneler için bir döngü gerekir ve döngüye + her bir iğne için karşılaştırma işlevini çağırarak birkaç iğne alır karşılaştırma fonksiyonu bulmak sürece.

En php.net tüm işlev isimlerini getirir ve bazı sonlar arar bir test komut dosyası atalım. Bu yalnızca bir anlık senaryo oldu ama Strcmp-imsi fonksiyonu + loop Eğer (bu durumda) basit pcre desen daha yavaş olacak kullanmak olursa olsun varsayalım.

count($hs)=5549
pcre: 4.377925157547 s
substr_compare: 7.951938867569 s
identical results: bool(true)

Bu sonuç iken dokuz farklı desen arayın. Sadece iki ('vesaire', 'ge') olsaydı her iki yöntem aynı zaman aldı.

(Herkes için açıktır ama kendini sentetik testlerde hataları her zaman orada değilsin? ;-)) Test script eleştirmek için çekinmeyin

<?php
/* get the test data
All the function names from php.net
*/
$doc = new DOMDocument;
$doc->loadhtmlfile('http://docs.php.net/quickref.php');
$xpath = new DOMXPath($doc);
$hs = array();
foreach( $xpath->query('//a') as $a ) {
  $hs[] = $a->textContent;
}
echo 'count($hs)=', count($hs), "\n";
// should find:
// ge, e.g. imagick_adaptiveblurimage
// ing, e.g. m_setblocking
// name, e.g. basename 
// ions, e.g. assert_options
$ns = array('yadda', 'ge', 'foo', 'ing', 'bar', 'name', 'abcd', 'ions', 'baz');
sleep(1);

/* test 1: pcre */
$start = microtime(true);
for($run=0; $run<100; $run++) {
  $matchesA = array();
  $pattern = '/(?:' . join('|', $ns) . ')$/';
  foreach($hs as $haystack) {
    if ( preg_match($pattern, $haystack, $m) ) {
      @$matchesA[$m[0]]+= 1;
    }
  }
}
echo "pcre: ", microtime(true)-$start, " s\n";
flush();
sleep(1);

/* test 2: loop + substr_compare */
$start = microtime(true);
for($run=0; $run<100; $run++) {
  $matchesB = array();
  foreach( $hs as $haystack ) {
    $hlen = strlen($haystack);
    foreach( $ns as $needle ) {
      $nlen = strlen($needle);
      if ( $hlen >= $nlen && 0===substr_compare($haystack, $needle, -$nlen) ) {
        @$matchesB[$needle]+= 1;
      }
    }
  }
}
echo "substr_compare: ", microtime(true)-$start, " s\n";
echo 'identical results: '; var_dump($matchesA===$matchesB);

Ben geriye bu yaklaşım olabilir;

if your string-ending list is fixed or varies rarely, I would start by preprocessing it to make it easy to match against, then grab the end of your string and see if it matches!

Örnek kod:

<?php

// Test whether string ends in predetermined list of suffixes
// Input: string to test
// Output: if matching suffix found, returns suffix as string, else boolean false
function findMatch($str) {
    $matchTo = array(
        2 => array( 'ge' => true, 'de' => true ),
        3 => array( 'foo' => true, 'bar' => true, 'baz' => true ),
        4 => array( 'abcd' => true, 'efgh' => true )
    );

    foreach($matchTo as $length => $list) {
        $end = substr($str, -$length);

        if (isset($list[$end]))
            return $end;
    }

    return $false;
}

?>

This might be an overkill but you can try the following. Create a hash for each entry of your search array and store them as keys in the array (that will be your lookup array).

Sonra zaman (e, de, CDE ve vb) adresinden giriş dizesi bir karakterin sonuna gitmek ve her tekrarda bir alt dize üzerinde bir hash hesaplamak. Bir karma senin arama dizideki ise, çok şey var.