Php bir dize formülü ile veri kümesini değerlendirme


9

Bir uygulamadaki bazı koşulları güncellemekle görevlendirildim. Değerlendirilecek bir veri setim var ve uygulamada şu şekilde kodlanmıştır:

$arr = array(
'a' => 'apple',
'b' => 'orange',
'c' => 1,
'd' => 2,
'e' => 5,
'f' => 'green',
'g' => 'red',
'h' => 'yellow',
)

$res1 = ($arr['a'] == 'apple') ? TRUE : FALSE;
$res2 = (($arr['b'] == $arr['f']) && ($arr['c'] < $arr['d']) ? TRUE : FALSE;
$res3 = (($arr['e'] == '5') && $res2) ?TRUE : FALSE;

ve bunun gibi...

Birçok yerde bakım yapmak bir kabus.

Ne aradığım aslında verileri değerlendirmek için sorgu dizesinde geçmek için bir yol yapmaktır. Başlangıç ​​için basit bir formül dizi olarak tanımlanabilir

$formula = ['a', '=', 'apple'];

function query($formula, $arr) {
    switch ($formula[1]) {
        case '=':
            return ($arr[$formula[0]] == $formula[2]);
        case '!=':
            return ($arr[$formula[0]]!= $formula[2]);
        case '>':
            return ($arr[$formula[0]] > $formula[2]);
        case '<':
            return ($arr[$formula[0]] == $formula[2]);
    }
}

Bu daha sonra genişletilebilir ve özyinelemeli olarak adlandırılabilir

$formula = [['a','=','apple'], 'AND', ['e','<','10']]

ama temelde aradığım şey formülleri aa string, saklamak gibi:

"((([a]="orange") OR ([c]<"4")) AND ([g]="red"))"

burada [] dizi anahtarlarını tanımlar

veya Excel'deki gibi bir şey

"AND(OR(IF('a'='orange'),IF('c'<4)),IF('g'='red'))"

Bunu yapmak için temiz bir çözüm var mı? Belki de gelecekte tüm kütüphanenin nasıl yapılacağına dair bir fikrim var.

Her seferinde koda yeni koşullar eklemek istemiyorum. Onlar zaten uygulamanın her yerinde. Konfigürasyonda saklamak ve tek bir yerde genişletmek veya değiştirmek daha iyi olur.

Herhangi bir yardım çok takdir etmek.


1
Bir değerlendirici yazmak karmaşık bir iştir, ancak ircmaxell'in bu soruya verdiği cevabı ve / veya ve karakter dizilerini de genişletmek için bir göz atabilirsiniz ; ya da benzeri bir şey Hesaplama motora bakmak PHPExcel
Mark Baker

1
"Temiz" bir çözüm, farklı işlevlere sahip bir sınıf kurmak ve birkaç dosyaya dahil etmek olacağını tahmin ediyorum. Kodu bir dize olarak saklamak ve daha sonra değerlendirmek için PHP sunar eval().

1
Teşekkürler @ MarkBaker, bunlara bir göz atabilirim. Tam olarak aradığım şey değil. Eval () kullanmak istemiyorum, bu formüller kullanıcılar tarafından kullanılacağı için bu çok tehlikeli olabilir. Bu daha kusursuz olmalıdır.
Pawel Jankowski

3
Bir "iç platform efekti" yaratmaya dikkat edin. Şimdiye kadar bize gösterdiklerinizden, birçok kod satırından tasarruf edeceğinizi hayal etmek zor. Tüm PHP sözdizimini tercih etmeyebilirsiniz, ancak herhangi bir PHP geliştiricisinin (veya C ++ veya Java geliştiricisinin) anlayabileceği bir standarttır. Bu denemek eğlenceli bir şey gibi görünse de, önce daha küçük ölçekli bir yan projede denemek daha iyi olabilir. Orada çalışırsa, büyük projeye yuvarlamayı düşünün.
John Doe

1
Bir RPN değerlendiricisi yazmak ve sürdürmek için daha basit bir görev olacaktır. Oldukça güçlü ve yanlış yapabileceğiniz daha az şey var. Bir dil düşüncesi olarak daha az kullanıcı dostudur.
Scara95

Yanıtlar:


1

Yani bu sadece hızlı bir çözüm, ama şu anda benim için çalışıyor.

$arr = array('a' => 'red','b' => 'blue');

$formula = ['[a]', '=', 'red'];

Formülde [a] varsa dizi anahtarı olarak kabul edilir.

function query($formula, $arr) {

    $query_operator=$formula[1];

    if (is_array($formula[0])) {
        //recursive call
        $query_left = query($formula[0], $arr);
    } else {
        //extracting string between brackets
        preg_match("/\[([^\]]*)\]/", $formula[0], $match);
        $query_left = $match ? $arr[($match[1])] : $formula[0];
    }

    if (is_array($formula[2])) {
        //recursive call
        $query_right = query($formula[2], $arr);
    } else {
        //extracting string between brackets
        preg_match("/\[([^\]]*)\]/", $formula[2], $match);
        $query_right = $match ? $arr[($match[1])] : $formula[2];
    }


    switch ($query_operator) {
        case '=':
            return ($query_left == $query_right);
        case '!=':
            return ($query_left != $query_right);
        case '>':
            return ($query_left > $query_right);
        case '<':
            return ($query_left == $query_right);
        case 'AND':
            return ($query_left && $query_right);
        case 'OR':
            return ($query_left || $query_right);
    }
}

Bu çözümde aşağıdaki gibi bir formülle çalışacaktır:

$formula = [['[a]', '=', 'red'], 'AND', ['[b]', '=', 'blue']];

Tam olarak istediğim şey değildi, ama işi yapıyor ve o kadar da korkunç değil (umarım). Bazı giriş denetimi ve hata işleme gerekir, ancak bu sadece bir örnektir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.