<?php
function parse($text)
{
// Find each character group: [...]
preg_match_all('/(.*?)(?:\[([^[\]]{1,30})\]|$)/s', $text, $matches, PREG_SET_ORDER
); $groups = [];
foreach ($matches as $match) {
// Prefix: foo
$groups []= $match[1];
}
// Group: [a-z0-9]
// For each range, add the chars to an array. ['a', 'b', ..., 'z', '0', ..., '9']
$chrs = [];
foreach ($ranges as $rng)
{
$chrs []= $rng[1];
}
else {
}
}
$groups []= $chrs;
}
}
return $groups;
}
function permute($groups, $index = 0)
{
$result = [];
if ($index >= count($groups)) {
// Reached the end. Return a single, empty result.
$result []= '';
}
{
// Current group is a simple string. Prepend it to all tail results.
$prefix = $groups[$index];
foreach (permute($groups, $index+1) as $s)
{
$result []= $prefix . $s;
}
}
else {
// Otherwise it is an array of characters. Prepend each to every tail result.
$chars = $groups[$index];
foreach (permute($groups, $index+1) as $s)
{
foreach ($chars as $ch) {
$result []= $ch . $s;
}
}
}
return $result;
}
$text = 'test[A-BXZ][0-1][x-z]foo';
$groups = parse($text);
$permutations = permute($groups);
?>
PD9waHAKICAgIGZ1bmN0aW9uIHBhcnNlKCR0ZXh0KQogICAgewogICAgICAgIC8vIEZpbmQgZWFjaCBjaGFyYWN0ZXIgZ3JvdXA6IFsuLi5dCiAgICAJcHJlZ19tYXRjaF9hbGwoJy8oLio/KSg/OlxbKFteW1xdXXsxLDMwfSlcXXwkKS9zJywgJHRleHQsICRtYXRjaGVzLCBQUkVHX1NFVF9PUkRFUik7CiAgICAgICAgJGdyb3VwcyA9IFtdOwogICAgICAgIGZvcmVhY2ggKCRtYXRjaGVzIGFzICRtYXRjaCkgewogICAgICAgICAgICBpZiAoIWVtcHR5KCRtYXRjaFsxXSkpIHsKICAgICAgICAgICAgICAgIC8vIFByZWZpeDogZm9vCiAgICAgICAgICAgICAgICAkZ3JvdXBzIFtdPSAkbWF0Y2hbMV07CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKCFlbXB0eSgkbWF0Y2hbMl0pKSB7CiAgICAgICAgICAgICAgICAvLyBHcm91cDogW2EtejAtOV0KICAgICAgICAgICAgICAgIC8vIEZvciBlYWNoIHJhbmdlLCBhZGQgdGhlIGNoYXJzIHRvIGFuIGFycmF5LiBbJ2EnLCAnYicsIC4uLiwgJ3onLCAnMCcsIC4uLiwgJzknXQogICAgICAgICAgICAgICAgJGNocnMgPSBbXTsKICAgICAgICAgICAgICAgIHByZWdfbWF0Y2hfYWxsKCcvKC4pKD86LSguKSk/LycsICRtYXRjaFsyXSwgJHJhbmdlcywgUFJFR19TRVRfT1JERVIpOwogICAgICAgICAgICAgICAgZm9yZWFjaCAoJHJhbmdlcyBhcyAkcm5nKQogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIGlmIChlbXB0eSgkcm5nWzJdKSkgewogICAgICAgICAgICAgICAgICAgICAgICAkY2hycyBbXT0gJHJuZ1sxXTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgZWxzZSB7CiAgICAgICAgICAgICAgICAgICAgICAgICRjaHJzID0gYXJyYXlfbWVyZ2UoJGNocnMsIHJhbmdlKCRybmdbMV0sICRybmdbMl0pKTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAkZ3JvdXBzIFtdPSAkY2hyczsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICByZXR1cm4gJGdyb3VwczsKICAgIH0KICAgIAogICAgZnVuY3Rpb24gcGVybXV0ZSgkZ3JvdXBzLCAkaW5kZXggPSAwKQogICAgewogICAgICAgICRyZXN1bHQgPSBbXTsKICAgICAgICBpZiAoJGluZGV4ID49IGNvdW50KCRncm91cHMpKQogICAgICAgIHsKICAgICAgICAgICAgLy8gUmVhY2hlZCB0aGUgZW5kLiBSZXR1cm4gYSBzaW5nbGUsIGVtcHR5IHJlc3VsdC4KICAgICAgICAgICAgJHJlc3VsdCBbXT0gJyc7CiAgICAgICAgfQogICAgICAgIGVsc2UgaWYgKGlzX3N0cmluZygkZ3JvdXBzWyRpbmRleF0pKQogICAgICAgIHsKICAgICAgICAgICAgLy8gQ3VycmVudCBncm91cCBpcyBhIHNpbXBsZSBzdHJpbmcuIFByZXBlbmQgaXQgdG8gYWxsIHRhaWwgcmVzdWx0cy4KICAgICAgICAgICAgJHByZWZpeCA9ICRncm91cHNbJGluZGV4XTsKICAgICAgICAgICAgZm9yZWFjaCAocGVybXV0ZSgkZ3JvdXBzLCAkaW5kZXgrMSkgYXMgJHMpCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICRyZXN1bHQgW109ICRwcmVmaXggLiAkczsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBlbHNlIHsKICAgICAgICAgICAgLy8gT3RoZXJ3aXNlIGl0IGlzIGFuIGFycmF5IG9mIGNoYXJhY3RlcnMuIFByZXBlbmQgZWFjaCB0byBldmVyeSB0YWlsIHJlc3VsdC4KICAgICAgICAgICAgJGNoYXJzID0gJGdyb3Vwc1skaW5kZXhdOwogICAgICAgICAgICBmb3JlYWNoIChwZXJtdXRlKCRncm91cHMsICRpbmRleCsxKSBhcyAkcykKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgZm9yZWFjaCAoJGNoYXJzIGFzICRjaCkgewogICAgICAgICAgICAgICAgICAgICRyZXN1bHQgW109ICRjaCAuICRzOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIAogICAgICAgIHJldHVybiAkcmVzdWx0OwogICAgfQogICAgCiAgICAkdGV4dCA9ICd0ZXN0W0EtQlhaXVswLTFdW3gtel1mb28nOwogICAgCiAgICAkZ3JvdXBzID0gcGFyc2UoJHRleHQpOwogICAgcHJpbnRfcigkZ3JvdXBzKTsKICAgIAogICAgJHBlcm11dGF0aW9ucyA9IHBlcm11dGUoJGdyb3Vwcyk7CiAgICBwcmludF9yKCRwZXJtdXRhdGlvbnMpOwo/Pg==