f = $functions !== null ? $functions : abj_service('functions'); $this->logger = $logging !== null ? $logging : abj_service('logging'); } /** * Extract N-grams from a URL string. * * Generates both bigrams (n=2) and trigrams (n=3) for optimal accuracy. * Research shows using both provides better typo detection than either alone. * * @param string $url * @param array $ngramSizes default [2, 3] * @return array{bi: array, tri: array} */ public function extractNGrams($url, $ngramSizes = [2, 3]) { if (empty($url)) { return ['bi' => [], 'tri' => []]; } $url = $this->f->strtolower($url); $originalLength = $this->f->strlen($url); if ($originalLength > self::MAX_URL_LENGTH) { $this->logger->infoMessage("WARNING: URL too long for N-gram extraction: {$originalLength} chars, truncating to " . self::MAX_URL_LENGTH . ". URL: " . $this->f->substr($url, 0, 100) . "..."); $url = $this->f->substr($url, 0, self::MAX_URL_LENGTH); } $result = []; $length = $this->f->strlen($url); foreach ($ngramSizes as $n) { $ngrams = []; for ($i = 0; $i <= $length - $n; $i++) { $ngram = $this->f->substr($url, $i, $n); $ngrams[$ngram] = true; } $key = ($n == 2) ? 'bi' : 'tri'; // Convert keys to strings to prevent PHP from converting numeric strings to integers $result[$key] = array_map('strval', array_keys($ngrams)); } /** @var array{bi: array, tri: array} $result */ return $result; } }