public static function expandMatchingPatterns($pattern, $actual)
{
if (self::isPcre($pattern)) {
return [$pattern, $actual];
}
$parts = preg_split('#(%)#', $pattern, -1, PREG_SPLIT_DELIM_CAPTURE);
for ($i = count($parts); $i >= 0; $i--) {
$patternX = implode(array_slice($parts, 0, $i));
$patternY = "{$patternX}%A?%";
if (self::isMatching($patternY, $actual)) {
$patternZ = implode(array_slice($parts, $i));
break;
}
}
foreach (['%A%', '%A?%'] as $greedyPattern) {
if (substr($patternX, -strlen($greedyPattern)) === $greedyPattern) {
$patternX = substr($patternX, 0, -strlen($greedyPattern));
$patternY = "{$patternX}%A?%";
$patternZ = $greedyPattern . $patternZ;
break;
}
}
$low = 0;
$high = strlen($actual);
while ($low <= $high) {
$mid = $low + $high >> 1;
if (self::isMatching($patternY, substr($actual, 0, $mid))) {
$high = $mid - 1;
} else {
$low = $mid + 1;
}
}
$low = $high + 2;
$high = strlen($actual);
while ($low <= $high) {
$mid = $low + $high >> 1;
if (!self::isMatching($patternX, substr($actual, 0, $mid), TRUE)) {
$high = $mid - 1;
} else {
$low = $mid + 1;
}
}
$actualX = substr($actual, 0, $high);
$actualZ = substr($actual, $high);
return [$actualX . rtrim(preg_replace('#[\\t ]*\\r?\\n#', "\n", $patternZ)), $actualX . rtrim(preg_replace('#[\\t ]*\\r?\\n#', "\n", $actualZ))];
}