I'm looking making a regex in php that gets data from the following format:
"1,2,3;7,1,3;1" returns an $matches array with "(1,2,3,7,1,3,1)"
"1" returns an $matches with "(1)"
"1;1;3;5;7;10;999" returns an $matches array with "(1,1,3,5,7,10,999)"
"1,1,1;2,5;3,4" doesn't pass since numbers are repeating within semicolon boundaries
"2,3,4;5,;" doesn't pass since it doesn't satisfy the format.
(Quotes in the examples are there to make them easier to read; they should not appear in the real results.)
The format is digit numbers separated by either commas or semicolons and within semicolons they don't repeat each other. It should not accept any other format.
I tried /(^(\d{1,3})$)|(([0-9]+)([,|;]{1}[0-9]+)+)/
but it didn't work. I also tried /[0-9]+([,|;]{1}[0-9]+)+/
but it didn't worked either. When I got the $matches array it didn't have the values I needed as depicted above.
I'm doing this in PHP 5.2. Thanks.
This particular problem has too much logic for regular expressions to be practical; this is how you could solve it with regular code:
// reduction function - keeps merging comma separated arguments
// until there's a duplicate or invalid item
function join_unique(&$result, $item)
{
if ($result === false) {
return false;
}
$items = explode(',', $item);
$numbers = array_filter($items, 'is_numeric');
if (count($items) != count($numbers)) {
return false;
}
$unique = array_unique($numbers);
if (count($unique) != count($numbers)) {
return false;
}
return array_merge($result, $numbers);
}
// main function - parse a string of comma / semi-colon separated values
function parse_nrs($str)
{
return array_reduce(explode(';', $str), 'join_unique', array());
}
var_dump(parse_nrs('1,2,3;7,1,3;1'));
var_dump(parse_nrs('1'));
var_dump(parse_nrs('1;1;3;5;7;10;999'));
var_dump(parse_nrs('1,1,1;2,5;3,4'));
var_dump(parse_nrs('2,3,4;5,;'));
Output:
array(7) {
[0]=>
string(1) "1"
[1]=>
string(1) "2"
[2]=>
string(1) "3"
[3]=>
string(1) "7"
[4]=>
string(1) "1"
[5]=>
string(1) "3"
[6]=>
string(1) "1"
}
array(1) {
[0]=>
string(1) "1"
}
array(7) {
[0]=>
string(1) "1"
[1]=>
string(1) "1"
[2]=>
string(1) "3"
[3]=>
string(1) "5"
[4]=>
string(1) "7"
[5]=>
string(2) "10"
[6]=>
string(3) "999"
}
bool(false)
bool(false)
See also: array_reduce()
array_unique()
It is impossible to do this in a single step. First you will need to check for the requirement of numbers repeating within a semicolon boundary, and then if it passes that checks split the string.
For example:
if (!preg_match('/\b(\d+),[^;]*\b\1\b/', $string)) {
$matches = preg_split('/[,;]/', $string);
} else {
$matches = NULL;
}
Ideone: http://ideone.com/Y8xf1N