How to do a exact word replacment in a string using PHP

时间:2015-07-13 21:05:34

标签: php regex string

I am using numbers as variable in a string to construct logic.

Here are example of the string that I have

(1 AND 2)
2  AND   1
(1 AND 2) OR  (3 AND 4)
1 AND (2  OR  3)

Then I have an array that looks like this

 $this->clause = array(
          '1' => (object) array('fieldId' => 'id',
                                'value' => 1),

          '2' => (object) array('fieldId' => 'cost',
                                'value' => 132),

          '3' => (object) array('fieldId' => 'name',
                                'value' => "Jay's LLC"),

          '4' => (object) array('fieldId' => 'first',
                                'value' => "Mike"),
        );

I am trying to replace the values in the string (1, 2, 3, and 4) with the corresponding values in the array.

Here how my strings will need to look like once done

first example "since the logic string does not contain the clause 3 and 4 then both will be added using 'AND' logic at the end of the string"

(1 AND 2) becomes
( id = '1' AND cost = '132' ) AND name = 'Jay\'s LLC' AND first = 'Mike'

Second example "since the logic string does not contain the clause 3 and 4 then both will be added using 'AND' logic at the end of the string"

    2  AND   1 becomes
    cost = '132' AND id = '1' AND name = 'Jay\'s LLC' AND first = 'Mike'

Third example "since the logic string does not contain the clause 4 then it will be added using 'AND' logic at the end of the string"

(1 AND 2) OR  (3 AND 4) becomes
( id = '1' AND cost = '132' ) OR (name = 'Jay\'s LLC')

Last example

1 AND (2  OR  3) AND 4 becomes
id = '1' (cost = '132' OR name = 'Jay\'s LLC') AND first = 'Mike'

Here is what I have tried

private function getAllWhereClauseStatements()
{
    $query = '';
    $totalClause = count($this->clause);

    if( $totalClause > 0 ){

        $query .= 'WHERE ';

        if( !empty($this->clauseLogic) ){
            $logic = '';
            $tmpLogic = $this->clauseLogic;
            foreach($this->clause as $key => $cl){
                $tmpLogic .= preg_replace('/\b'.$key.'\b/u', $this->getWhereClause($cl), $tmpLogic);
                $this->clause->isUsed = 1;
            }

            if(! empty($logic) ){
                $query .= ' ( ' . $logic . ' ) ';
            }

            foreach($this->clause as $key => $cl){
                if( !isset($this->clause->isUsed) || !$this->clause->isUsed){
                    $query .= ' AND ' . $this->getWhereClause($cl);
                    $this->clause->isUsed = 1;
                }
            }
        }
    }

    return $query;
}



private function getWhereClause($cl)
{
    return $cl->fieldId . ' = ' . $cl->value;
}

I have 2 problems that I need help with

  1. I get a "Warning: Attempt to assign property of non-object" on the line $this->clause->isUsed = 1;
  2. I am trying to handle the last example "i.e. 1 AND (2 OR 3)" I get the following

    1 AND (2 OR 3) 1 AND (2 OR name = 'Jay\'s LLC' ) 1 AND (2 OR 3) 1 AND (2 OR name = 'Jay\'s LLC' ) 1 AND (cost <> '132' OR 3) 1 AND (cost <> '132' OR name = 'Jay\'s LLC' ) 1 AND (cost <> '132' OR 3) 1 AND (cost <> '132' OR name = 'Jay\'s LLC' ) id = '1' AND (2 OR 3) id = '1' AND (2 OR name = 'Jay\'s LLC' ) id = '1' AND (2 OR 3) id = '1' AND (2 OR name = 'Jay\'s LLC' ) id = '1' AND (cost <> '132' OR 3) id = '1' AND (cost <> '132' OR name = 'Jay\'s LLC' ) id = '1' AND (cost <> '132' OR 3) id = '1' AND (cost <> '132' OR name = 'Jay\'s LLC' )

The issue seems to be how I am trying to do a work replacement

How to correct the 2 issues that I am having?

EDITED

I fixed the first issue by the line changing

$this->clause->isUsed = 1;

to

$this->clause[$key]->isUsed = 1;

2 个答案:

答案 0 :(得分:0)

我发现并修复了问题

private function getAllWhereClauseStatements()
{
    $query = '';
    $totalClause = count($this->clause);

    if( $totalClause > 0 || ! empty($this->baseClientId) ){

        $query .= 'WHERE ';

        if( !empty($this->clauseLogic) ){
            $logic = $this->clauseLogic;
            $charArray = array();
            foreach($this->clause as $key => $cl){
                $charArray[] = $key;
            } 

            $charList = implode(',', $charArray);

            if( !empty($charList) ){
                $wordsCount = str_word_count($logic, 1, $charList);
            } else {
                $wordsCount = str_word_count($logic, 1);
            }

            $words = array_count_values($wordsCount);

            foreach($this->clause as $key => $cl){

                if(isset($words[$key]) && $words[$key] > 0){
                    $logic = preg_replace('/\b'.$key.'\b/u', $this->getWhereClause($cl) , $logic);
                    $this->clause[$key]->isUsed = 1;                    
                }

            }

            if(! empty($logic) ){
                $query .= ' ( ' . $logic . ' ) ';
            }

            foreach($this->clause as $key => $cl){
                if( !isset($cl->isUsed) ){
                    $query .= ' AND ' . $this->getWhereClause($cl);
                    $this->clause[$key]->isUsed = 1;
                }
            }
        }

    }

    return $query;
}

答案 1 :(得分:0)

我的印象是你过度复杂化了一些问题(留下问题,你应该尝试通过编写自己的查询构建器来重新发明轮子,并且绝对不会进入主题性能讨论))。

考虑以下代码替代方法(伪,未经测试!):

private function getWhere()
{
    // only do something if clause and logic are given
    if(empty($this->clause) || empty($this->clauseLogic) {
        return '';
    }

    // fetch the required properties so we can safely alter them
    $conditions = $this->clause;
    $logic = $this->clausLogic;

    // turn the $conditions objects into SQL strings
    array_walk($conditions, function(&$condition) {
        $condition = $condition->fieldid . '="' . $condition->value . '"';
    });

    // append missing conditions to the logic
    foreach ($conditions as $key => $value) {
       if (strpos($logic, $key) === false) {
          $logic .= ' AND ' . $key;
       }
    }

    // do the replacement and return
    return 'WHERE ' . strtr($logic, $conditions);
}

正如我所说,未经测试,但我相信它应该与您尝试使用代码实现的目标相同。而且你必须承认它读起来要容易得多(因此本身就更容易调试)。