File size: 2.12Kb
<?php declare(strict_types=1);
/**
* @package s9e\RegexpBuilder
* @copyright Copyright (c) 2016-2022 The s9e authors
* @license http://www.opensource.org/licenses/mit-license.php The MIT License
*/
namespace s9e\RegexpBuilder\Passes;
use const false, true;
use function array_slice, count;
/**
* Replaces (?:axx|ayy) with a(?:xx|yy)
*/
class MergePrefix extends AbstractPass
{
/**
* {@inheritdoc}
*/
protected function runPass(array $strings): array
{
$newStrings = [];
foreach ($this->getStringsByPrefix($strings) as $prefix => $strings)
{
$newStrings[] = (isset($strings[1])) ? $this->mergeStrings($strings) : $strings[0];
}
return $newStrings;
}
/**
* Get the number of leading elements common to all given strings
*
* @param array[] $strings
* @return integer
*/
protected function getPrefixLength(array $strings): int
{
$len = 1;
$cnt = count($strings[0]);
while ($len < $cnt && $this->stringsMatch($strings, $len))
{
++$len;
}
return $len;
}
/**
* Return given strings grouped by their first element
*
* NOTE: assumes that this pass is run before the first element of any string could be replaced
*
* @param array[] $strings
* @return array[]
*/
protected function getStringsByPrefix(array $strings): array
{
$byPrefix = [];
foreach ($strings as $string)
{
$byPrefix[$string[0]][] = $string;
}
return $byPrefix;
}
/**
* Merge given strings into a new single string
*
* @param array[] $strings
* @return array
*/
protected function mergeStrings(array $strings): array
{
$len = $this->getPrefixLength($strings);
$newString = array_slice($strings[0], 0, $len);
foreach ($strings as $string)
{
$newString[$len][] = array_slice($string, $len);
}
return $newString;
}
/**
* Test whether all given strings' elements match at given position
*
* @param array[] $strings
* @param integer $pos
* @return bool
*/
protected function stringsMatch(array $strings, int $pos): bool
{
$value = $strings[0][$pos];
foreach ($strings as $string)
{
if (!isset($string[$pos]) || $string[$pos] !== $value)
{
return false;
}
}
return true;
}
}