⟨/⟩ Nts/55_Backend/ModificationSelection/ModificationNameRecognition.cs

116 строк · в начало

using Rugrid.Sdaid.Notation.Documents;

namespace Rugrid.Sdaid.Epas.Nts.Backend.ModificationSelection
{
    /// <summary>
    /// Распознавание в наименовании ТС марки, модели и остатка наименования без марки.
    /// Чистый алгоритм: не строит группы, не фильтрует справочник по нормам и не решает,
    /// что делать с пустым результатом.
    /// </summary>
    public class DOC_ModificationNameRecognition : IApplicationServiceDocument, IHasStructuralLinks, IFolder<NtsBackendFolder>
    {
        public SdaidLink[] Links => new[]
        {
            Rel.Uses<Rugrid.Sdaid.Epas.Nts.Domain.DOC_Vehicle>(),
            Rel.Uses<Rugrid.Sdaid.Epas.Nts.Domain.DOC_VehicleMark>(),
            Rel.Uses<Rugrid.Sdaid.Epas.Nts.Domain.DOC_VehicleMarkAlias>(),
            Rel.Uses<Rugrid.Sdaid.Epas.Nts.Domain.DOC_VehicleModel>(),
        };

        public static string _refName = "Распознавание марки и модели ТС";

        public string Name => "Распознавание марки и модели ТС";

        public string Description =>
            @"Распознавание в наименовании ТС марки, модели и остатка наименования без марки — чистый алгоритм без построения групп и фильтрации справочника по нормам.";

        public string Version => "0.1";
        public string Status => "draft";
        public string[] Comments => new string[0];

        public static string Purpose = $"""
            ## Назначение

            Алгоритм отвечает только за разбор строки наименования ТС
            ({SdaidAnchors.RefTo<Rugrid.Sdaid.Epas.Nts.Domain.DOC_Vehicle>()}, «Марка и модель
            базы ТС»): какая марка и какая модель распознаны и какая часть строки осталась после
            удаления марки.

            Он **не** строит базовую группу, **не** фильтрует модификации по нормам и топливу и
            **не** решает, что делать с пустым результатом — это ответственность вызывающих
            процедур:

            - автоподбор группы модификаций —
              {SdaidAnchors.RefTo<Rugrid.Sdaid.Epas.Nts.Backend.ModificationSelection.DOC_ModificationGroupSelection>()};
            - установка маски в окне подбора —
              {SdaidAnchors.RefTo<Rugrid.Sdaid.Epas.Nts.Ui.DOC_ModificationSelectionModal>()};
            - предложение марки и модели в карточке модификации —
              {SdaidAnchors.RefTo<Rugrid.Sdaid.Epas.Nts.Ui.DOC_VehicleModificationCard>()}.
            """;

        public static string Normalization = $"""
            ## Нормализация сравнений

            Все сравнения идут по нормализованному ключу: нижний регистр, `ё` → `е`,
            транслитерация кириллицы в латиницу, удаление всех небуквенно-цифровых символов.
            Токены — части строки после разделителей длиной от 2 символов.
            """;

        public static string Brand = $"""
            ## Распознавание марки

            **`DetectBrand(name)`** — каноническая марка по мастер-списку марок (drom +
            постановление + доменный список) с алиасами
            ({SdaidAnchors.RefTo<Rugrid.Sdaid.Epas.Nts.Domain.DOC_VehicleMarkAlias>()}). Ключи
            проверяются от длинных к коротким; результат — первое совпадение:

            - для любого ключа — равенство токену;
            - цифровой ключ — только равенство токену, без префиксов и подстрок;
            - ключ длиной ≥ 3 — токен начинается с ключа;
            - ключ длиной ≥ 4 — ключ входит в нормализованное имя целиком.

            Если совпадений нет — пустая строка.

            **`DetectBrandIn(rows, name)`** — марка только из справочника вида ТС. Сначала
            берётся `DetectBrand(name)`; результат принимается, если такая марка есть среди марок
            строк `rows`. Если каноническая марка в группе не найдена, повторно ищется самая
            длинная марка среди марок `rows` по тем же критериям совпадения. Итог всегда — марка
            из справочника вида ТС, поэтому омонимы мастер-списка не подставляются: например,
            «Genesis» в «HYUNDAI GENESIS», где в справочнике это модель Hyundai.

            Мастер-список марок — справочник {SdaidAnchors.RefTo<Rugrid.Sdaid.Epas.Nts.Domain.DOC_VehicleMark>()}
            (наименование), алиасы — связанные записи
            {SdaidAnchors.RefTo<Rugrid.Sdaid.Epas.Nts.Domain.DOC_VehicleMarkAlias>()}: токен
            сопоставляется либо с наименованием марки, либо с алиасом любой её связанной записи.
            """;

        public static string Model = $"""
            ## Распознавание модели

            **`DetectModel(rows, name)`** — среди моделей строк `rows`
            ({SdaidAnchors.RefTo<Rugrid.Sdaid.Epas.Nts.Domain.DOC_VehicleModel>()}) выбирается
            модель с самым длинным нормализованным наименованием (от 2 символов), которое целиком
            входит в нормализованное имя ТС. Если ни одна не входит — пустая строка.
            """;

        public static string NameRemainder = $"""
            ## Остаток наименования ТС

            **`BuildNameRemainder(name)`** — часть строки «Марка и модель базы ТС» после удаления
            марки: строка разбивается на токены, из них удаляются токены, являющиеся ключами марок
            мастер-списка, оставшиеся токены (от 2 символов) склеиваются через пробел.

            Это не отдельное поле ТС и не «модификация»: остаток — рабочий текст для поиска.
            Вызывающие используют его по-разному:

            - автоподбор и маска — как подстроку для фильтра по полному наименованию модификации
              (когда модель не распознана);
            - карточка модификации — как предложение в поле «Модель».

            Источник строки — «Марка и модель базы ТС». Использовать ли для спецтехники ещё и
            «Модель спец. автомобиля» — открытый вопрос
            {SdaidAnchors.RefTo<Rugrid.Sdaid.Epas.Nts.Epics.NtsFuelCalc.OQ_ModificationSelection>()}.
            """;
    }
}