Split strings in array to form three-element subarrays

66 views Asked by At

I am practising with the AdventureWorks database for now and I will be receiving strings like the following: SalesOrderNumber=SOH123 and CustomerID=1. The strings may not always contain =, as they may be >, <, >=, <=, !=, <>.

Ideally, I would like to split each string into 3 fields - the database column to query, the comparison (e.g. =, >, !=, etc) and the value to search for.

I can achieve what I want with lots of code, comparing character by character, but I am hoping someone can suggest a really simple way to do this, as I am sure this must be a fairly common task for websites.

I don't want to just use the strings as they come through, as I need to sanitise them first. I also don't want to send bad queries to the database that may generate SQL errors.

2

There are 2 answers

0
mickmackusa On BEST ANSWER

It is indirect and feasibly inefficient to make calls of explode() within nested loops with break condition.

I recommend preg_split() as the right tool for the job. Create a capture group containing a character class of whitelisted symbols. Allow a maximum of 3 elements as its return value. Use the PREG_SPLIT_DELIM_CAPTURE flag to inform the function to preserve the delimiting comparison operators when exploding the string into three parts.

Code: (Demo)

var_export(
    array_map(
        fn($v) => preg_split(
            '/([!<=>]+)/',
            $v,
            3,
            PREG_SPLIT_DELIM_CAPTURE
        ),
        $array
    )
);

Output:

array (
  0 => 
  array (
    0 => 'SalesOrderNumber',
    1 => '=',
    2 => 'SOH123',
  ),
  1 => 
  array (
    0 => 'CustomerID',
    1 => '=',
    2 => '1',
  ),
  2 => 
  array (
    0 => 'BigOrEqual',
    1 => '>=',
    2 => '44',
  ),
  3 => 
  array (
    0 => 'SmallOrEqual',
    1 => '<=',
    2 => '67',
  ),
  4 => 
  array (
    0 => 'NotEqual',
    1 => '!=',
    2 => '123',
  ),
  5 => 
  array (
    0 => 'NotEqual',
    1 => '<>',
    2 => '2000',
  ),
  6 => 
  array (
    0 => 'Smaller',
    1 => '<',
    2 => '21',
  ),
  7 => 
  array (
    0 => 'Bigger',
    1 => '>',
    2 => '12',
  ),
)
1
masterguru On

This is my aproach using foreach, explode and array functions:

$strings = [
    'SalesOrderNumber=SOH123',
    'CustomerID=1',
    'BigOrEqual>=44',
    'SmallOrEqual<=67',
    'NotEqual!=123',
    'NotEqual<>2000',
    'Smaller<21',
    'Bigger>12',
];
function explodeOperators(array $strings) : array
{
    $operators = ['>=','<=','!=','<>','<','>','=']; // do not change this order
    $result = [];
    foreach ($strings as $expression) {
        $found = false;
        foreach ($operators as $operator) {
            $exploded = explode($operator, $expression);
            if (count($exploded) > 1 and $found === false) {
                $found = true;
                array_splice($exploded, 1, 0, $operator);
                $result[] = $exploded;
            }
        }
    }
    return $result;
}
$result = explodeOperators($strings);
print_r($result);

That will result:

Array
(
    [0] => Array
        (
            [0] => SalesOrderNumber
            [1] => =
            [2] => SOH123
        )

    [1] => Array
        (
            [0] => CustomerID
            [1] => =
            [2] => 1
        )

    [2] => Array
        (
            [0] => BigOrEqual
            [1] => >=
            [2] => 44
        )

    [3] => Array
        (
            [0] => SmallOrEqual
            [1] => <=
            [2] => 67
        )

    [4] => Array
        (
            [0] => NotEqual
            [1] => !=
            [2] => 123
        )

    [5] => Array
        (
            [0] => NotEqual
            [1] => <>
            [2] => 2000
        )

    [6] => Array
        (
            [0] => Smaller
            [1] => <
            [2] => 21
        )

    [7] => Array
        (
            [0] => Bigger
            [1] => >
            [2] => 12
        )

)