seed-product-features: two more icon-matching tiers
- token-containment pass: theme words inside the card title (ManagementFoundation -> "Aetria management foundation") - last-pair rule: a complete set (#icons == #cards) with exactly one icon and one card left over pairs them (FlexibleConnection, EndToEndEncryption, HighPerformance, 4KSourcetoDisplays, AVoverIP) - genuine mismatches (aligo-workstation, EZ-TV Platform, AvediaPlatform Artio icons) still stay unmatched for the editors Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
46b12d4a58
commit
6ff9c3e7a8
1 file changed
+43
@@ -131,6 +131,36 @@ final class SeedProductFeaturesCommand extends Command
|
||||
}
|
||||
}
|
||||
|
||||
// second pass: token containment, e.g. theme "ManagementFoundation"
|
||||
// inside the card title "Aetria management foundation"
|
||||
foreach ($pairs as $i => $pair) {
|
||||
if (isset($pair['icon'])) {
|
||||
continue;
|
||||
}
|
||||
foreach (array_keys(array_diff_key($iconByTheme, $usedThemes)) as $theme) {
|
||||
$titleTokens = $this->tokens($pair['title']);
|
||||
$themeTokens = $this->tokens($theme);
|
||||
if ($titleTokens !== [] && $themeTokens !== []
|
||||
&& (array_diff($themeTokens, $titleTokens) === [] || array_diff($titleTokens, $themeTokens) === [])
|
||||
) {
|
||||
$pairs[$i]['icon'] = $iconByTheme[$theme];
|
||||
$usedThemes[$theme] = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// last pair standing: a complete set (#icons == #cards) with exactly
|
||||
// one icon and one card left over - they belong to each other
|
||||
if (count($iconByTheme) === count($pairs)) {
|
||||
$freeThemes = array_keys(array_diff_key($iconByTheme, $usedThemes));
|
||||
$freePairs = array_keys(array_filter($pairs, static fn(array $p): bool => !isset($p['icon'])));
|
||||
if (count($freeThemes) === 1 && count($freePairs) === 1) {
|
||||
$pairs[$freePairs[0]]['icon'] = $iconByTheme[$freeThemes[0]];
|
||||
$usedThemes[$freeThemes[0]] = true;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($pairs as $pair) {
|
||||
$output->writeln(sprintf(
|
||||
' "%s"%s%s',
|
||||
@@ -281,6 +311,19 @@ final class SeedProductFeaturesCommand extends Command
|
||||
return $bestDistance <= 3 ? $best : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lowercase word list (camelCase split, stop words removed) for the
|
||||
* token-containment pass.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
private function tokens(string $value): array
|
||||
{
|
||||
$words = preg_split('/(?=[A-Z][a-z])|[^A-Za-z0-9]+/', $value, -1, PREG_SPLIT_NO_EMPTY) ?: [];
|
||||
$words = array_map(static fn(string $w): string => mb_strtolower($w), $words);
|
||||
return array_values(array_filter($words, static fn(string $w): bool => !in_array($w, self::STOPWORDS, true)));
|
||||
}
|
||||
|
||||
/** lowercase, letters/digits only; optionally with stop words removed (camelCase themes are split first) */
|
||||
private function norm(string $value, bool $dropStopwords): string
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user