This is for an osCommerce contribution called
(“Automatically add multiple products with attribute to cart from external source”)
This existing code uses sscanf to ‘explode’ a string that represents a
– product ID,
– a productOption,
– and quantity:
sscanf('28{8}17[1]', '%d{%d}%d[%f]',
$productID, // 28
$productOptionID, $optionValueID, //{8}17 <--- Product Options!!!
$productQuantity //[1]
);
This works great if there is only 1 ‘set’ of Product Options (e.g. {8}17).
But this procedure needs to be adapted so that it can handle multiple Product Options, and put them into an array, e.g.:
'28{8}17{7}15{9}19[1]' //array(8=>17, 7=>15, 9=>19)
OR
'28{8}17{7}15[1]' //array(8=>17, 7=>15)
OR
'28{8}17[1]' //array(8=>17)
Thanks in advance. (I’m a pascal programmer)
3
Answers
You should not try to do complex recursive parses with one sscanf. Stick it in a loop. Something like:
Maybe regular expressions may be interesting
To get the other things
According the comment a little update
sscanf()
is not the ideal tool for this task because it doesn’t handle recurring patterns and I don’t see any real benefit in type casting or formatting the matched subexpressions.If this was purely a text extraction task (in other words your incoming data was guaranteed to be perfectly formatted and valid), then I could have recommended a cute solution that used
strtr()
andparse_str()
to quickly generate a completely associative multi-dimensional output array.However, when you commented "with sscanf I had an infinite loop if there is a missing bracket in the string (because it looks for open and closing {}s). Or if I leave out a value. But with your regex solution, if I drop a bracket or leave out a value", then this means that validation is an integral component of this process.
For that reason, I’ll recommend a regex pattern that both validates the string and breaks the string into its meaningful parts. There are several logical aspects to the pattern but the hero here is the
G
metacharacter that allows the pattern to "continue" matching where the pattern last finished matching in the string. This way we have an array of continuous fullstring matches to pull data from when creating your desired multidimensional output.The pattern
^d+(?=.+[d+]$)|G(?!^)(?:{Kd+}d+|[Kd(?=]$))
inpreg_match_all()
generates the following type of output in the fullstring element ([0]
):The first branch in the pattern (
^d+(?=.+[d+]$)
) validates the string to start with theid
number and ends with a square brace wrapped number representing thequantity
.The second branch begins with the "continue" character and contains two logical branches itself. The first matches an option expression (and forgets the leading
{
thanks toK
) and the second matches the number in the quantity expression.To create the associative array of options, target the "middle" elements (if there are any), then split the strings on the lingering
}
and assign these values as key-value pairs.This is a direct solution because it only uses one
preg_
call and it does an excellent job of validating and parsing the variable length data.Code: (Demo with a battery of test cases)