Add family_name and bracket-adjacent placement signals for .asm scanning

Two more real placement forms found by comparing against Creo BOM reports:

- A sub-assembly can be referenced only through a "family_name\0<code>\0"
  metadata field instead of a textual "Componente ID" placement or the
  doubled-NUL pattern (case 9284202452 inside 9284208188_D400.asm, which
  contains 9284202452_C01/_C02/_C03 - previously dropped entirely, along
  with its three children).
- A bare numeric code immediately followed by a family-table bracket
  (<code><GENERIC>, e.g. bearing instances like 2510060303<CUSCI_ACBB7>)
  is a real reference to that instance, even though only the generic file
  is indexed on disk. Previously the instance code silently vanished before
  ever reaching the DB lookup; now it survives placement filtering and ends
  up in the "scartati" (discarded) list instead, so it's traceable rather
  than invisible.

docs/formato-asm.md documents both, bringing the total to four recognized
placement forms.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
davideandClaude Sonnet 5 committed 2026-09-17 16:14:52 +02:00
1 parent a7e0df0247
commit e7b5d85f6b
3 files changed
+61 -17

No files matched your search

+22 -7
View File
@@ -49,18 +49,28 @@ HashSet<string> EstraiCodiciReferenziati(string percorsoAsm)
// riferimenti al proprio assieme padre (nome sessione/file) o a codici superati/
// rinominati (caso "fantasma", docs/formato-asm.md) ripetono comunque il codice più
// volte pur non essendo mai un componente vero. Per questi si richiede un vero
// placement, in una delle due forme osservate nel binario: "Componente ID N
// placement, in una delle quattro forme osservate nel binario: "Componente ID N
// (<codice>...)"/"Component id N (<codice>...)" (la stringa cambia con la
// localizzazione Creo del file), oppure il codice ripetuto due volte di seguito
// separato da un singolo byte NUL ("<codice>\0<codice>\0", osservato per componenti di
// family table non-UNI, es. cuscinetti "CUSCI_..."). Non si applica alle varianti con
// suffisso "_..." né alle istanze family table UNI: in alcuni file il placement
// localizzazione Creo del file); il codice ripetuto due volte di seguito separato da
// un singolo byte NUL ("<codice>\0<codice>\0", osservato per componenti di family
// table non-UNI, es. cuscinetti "CUSCI_..."); il campo "family_name\0<codice>\0"
// (osservato una sola volta per file, su un sotto-assieme referenziato come family
// table generica invece che con un placement testuale esplicito); oppure il codice
// seguito immediatamente da un bracket "<codice><GENERICO>" - l'istanza di una family
// table non-UNI vista nel nome (es. "2510060303<CUSCI_ACBB7>", un cuscinetto): il
// codice dell'istanza non è mai indicizzato a sé (solo il generico tra "<" e ">" lo è,
// vedi sotto), ma questo segnale lo fa comunque sopravvivere fino alla ricerca nel DB
// invece di scomparire in silenzio come "nudo senza placement" - lì verrà comunque
// scartato come "non in indice", ma in modo tracciabile. Non si applica alle varianti
// con suffisso "_..." né alle istanze family table UNI: in alcuni file il placement
// riporta solo il nome istanza/generico senza il dettaglio del suffisso o del bracket
// "<...>", che vive altrove nei metadati - lì l'occorrenza ripetuta resta l'unico
// segnale disponibile.
bool HaPlacement(string codice) =>
Regex.IsMatch(testo, $@"Component(?:e)? id \d+ \([^()]*{Regex.Escape(codice)}[^()]*\)", RegexOptions.IgnoreCase)
|| testo.Contains(codice + "\0" + codice + "\0");
|| testo.Contains(codice + "\0" + codice + "\0")
|| testo.Contains("family_name\0" + codice + "\0")
|| testo.Contains(codice + "<");
candidati.RemoveWhere(c => Regex.IsMatch(c, @"^\d{8,12}[A-Za-z]{0,2}$") && !HaPlacement(c));
return candidati;
@@ -84,8 +94,13 @@ Dictionary<string, List<(string Tipo, string Percorso)>> CercaComponenti(IReadOn
using var command = connection.CreateCommand();
var nomiParametri = codici.Select((_, i) => $"@c{i}").ToList();
// Lo stesso codice+tipo può esistere in più cartelle radice (duplicati/copie storiche
// sulla share, es. un generico family table ripetuto in 5 progetti scollegati): ordinato
// per data_modifica DESC, si tiene solo il più recente per codice+tipo (stessa regola di
// Form1.RisolviAlberoComponenti, vedi docs/formato-asm.md).
command.CommandText = "SELECT codice, tipo_file, percorso_completo FROM files_ultima_versione "
+ $"WHERE LOWER(codice) IN ({string.Join(",", nomiParametri)}) AND LOWER(tipo_file) IN ('prt', 'asm')";
+ $"WHERE LOWER(codice) IN ({string.Join(",", nomiParametri)}) AND LOWER(tipo_file) IN ('prt', 'asm') "
+ "ORDER BY codice, tipo_file, data_modifica DESC";
int i = 0;
foreach (var codice in codici)
command.Parameters.AddWithValue(nomiParametri[i++], codice.ToLowerInvariant());