- Batch the DB lookup per file instead of per code in scripts/ExtractCreoStrings.cs: files_ultima_versione is an unmaterialized view, so each query rescanned the whole files table (~230ms) - batching cuts a multi-minute BFS to seconds. - Widen the code regex to accept a revision letter and a "_..." suffix together (e.g. "9284200366A_C01"), and purely numeric "_NNNN" suffixes (e.g. dimensional variants like "2702220182_8188"), not just letter+digits. - Require bare digit-only candidates to also appear inside a real "Componente ID N (...)"/"Component id N (...)" placement, filtering out incidental references to a containing assembly's own code. - scripts/ExtractCreoStrings.cs now reports only the direct references of the given .asm (one level, matching Creo's own tree for that file) instead of recursing into sub-assemblies. - Port the regex and placement-check refinements to the production AssemblyComponentScanner.cs used by the app's "Trova componenti referenziati" and "Verifica completezza" phases. - Document the new false-positive categories (parent/container self-reference, suppressed/removed components with residual placement, placement missing suffix/bracket detail) in docs/formato-asm.md, generalized beyond the specific assemblies used to find them. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
68 lines
3.7 KiB
C#
68 lines
3.7 KiB
C#
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
|
|
namespace CadSearchGui;
|
|
|
|
/// <summary>
|
|
/// Estrae i codici componente referenziati dentro un file .asm Pro-E/Creo.
|
|
/// Il formato è per lo più binario, ma i codici dei sotto-componenti compaiono
|
|
/// come stringhe ASCII leggibili al suo interno: si scansiona il file come testo
|
|
/// cercando pattern che assomigliano a un codice (stesso stile usato nei nomi file,
|
|
/// vedi Indexer.FilenameRegex) e si lascia poi al chiamante il compito di verificarli
|
|
/// contro l'indice DB, che scarta automaticamente i falsi positivi (numeri che non
|
|
/// corrispondono a nessun codice reale).
|
|
///
|
|
/// Verificato su un caso reale confrontando con un report BOM generato da Creo: i
|
|
/// riferimenti veri compaiono più volte nel file (una volta per feature/placement),
|
|
/// mentre il rumore binario casuale che assomiglia a un codice compare quasi sempre
|
|
/// una sola volta. Si scartano quindi i candidati con una sola occorrenza.
|
|
///
|
|
/// Falso positivo noto ed escluso: gli ID interni di viste salvate, nel formato
|
|
/// "ModelView#<numero>", hanno la stessa forma di un codice (8-12 cifre) e
|
|
/// compaiono più volte come un riferimento vero. Vedi docs/formato-asm.md.
|
|
///
|
|
/// Viti/dadi/rosette normalizzati UNI sono family table Creo: il nome che compare nel
|
|
/// binario (es. "R6--_-_U6592<UNI6592>") è la singola istanza, non un file separato
|
|
/// su disco - il file reale indicizzato è il generico "uni6592.prt.<versione>", quindi
|
|
/// va estratto solo il contenuto tra "<" e ">". Vedi docs/formato-asm.md.
|
|
///
|
|
/// Lettera di revisione e suffisso "_..." possono comparire insieme sullo stesso codice
|
|
/// (es. "9284200366A_C01"), e il suffisso dopo "_" può essere puramente numerico (es.
|
|
/// "2702220182_8188", una variante dimensionale, non lettera+cifre come "_C01"/"_D100").
|
|
///
|
|
/// Un codice "nudo" (senza suffisso "_..." e senza bracket UNI) ripetuto più volte non
|
|
/// basta: può trattarsi del riferimento al nome di un altro assieme che lo contiene (non
|
|
/// noto a priori, quindi non escludibile per confronto diretto come il proprio codice) o
|
|
/// di un residuo di feature soppresse/superate (vedi docs/formato-asm.md). Per questi si
|
|
/// richiede anche un vero placement "Componente ID N (<codice>...)"/
|
|
/// "Component id N (<codice>...)" (la stringa cambia con la localizzazione Creo del
|
|
/// file). Non si applica alle varianti con suffisso o bracket 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ì resta necessaria la sola euristica delle
|
|
/// occorrenze ripetute.
|
|
/// </summary>
|
|
static class AssemblyComponentScanner
|
|
{
|
|
private static readonly Regex CodiceRegex = new(
|
|
@"(?<!ModelView#)\b\d{8,12}[A-Za-z]{0,2}(?:_[A-Za-z]?\d{2,4})?\b|(?<=<)UNI\d+(?=>)", RegexOptions.Compiled);
|
|
private static readonly Regex CodiceNudoRegex = new(@"^\d{8,12}[A-Za-z]{0,2}$", RegexOptions.Compiled);
|
|
private const int OccorrenzeMinime = 2;
|
|
|
|
public static HashSet<string> EstraiCodiciReferenziati(string percorsoAsm)
|
|
{
|
|
var testo = Encoding.Latin1.GetString(File.ReadAllBytes(percorsoAsm));
|
|
var occorrenze = new Dictionary<string, int>();
|
|
foreach (Match m in CodiceRegex.Matches(testo))
|
|
{
|
|
occorrenze[m.Value] = occorrenze.GetValueOrDefault(m.Value) + 1;
|
|
}
|
|
var candidati = occorrenze.Where(kv => kv.Value >= OccorrenzeMinime).Select(kv => kv.Key).ToHashSet();
|
|
|
|
bool HaPlacement(string codice) =>
|
|
Regex.IsMatch(testo, $@"Component(?:e)? id \d+ \([^()]*{Regex.Escape(codice)}[^()]*\)", RegexOptions.IgnoreCase);
|
|
|
|
candidati.RemoveWhere(c => CodiceNudoRegex.IsMatch(c) && !HaPlacement(c));
|
|
return candidati;
|
|
}
|
|
}
|