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) {
|
foreach ($pairs as $pair) {
|
||||||
$output->writeln(sprintf(
|
$output->writeln(sprintf(
|
||||||
' "%s"%s%s',
|
' "%s"%s%s',
|
||||||
@@ -281,6 +311,19 @@ final class SeedProductFeaturesCommand extends Command
|
|||||||
return $bestDistance <= 3 ? $best : null;
|
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) */
|
/** lowercase, letters/digits only; optionally with stop words removed (camelCase themes are split first) */
|
||||||
private function norm(string $value, bool $dropStopwords): string
|
private function norm(string $value, bool $dropStopwords): string
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in new issue
Block a user