using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; namespace MvdLiteSnoop.MvdLite; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.RegularExpressions; /// /// 用于保存从MVDLite文本中解析出的结构化数据的类。 /// public class MvdData { /// /// 文件头部的元数据。 /// 例如:# MVDLite_Version = '2.5.0.0' /// public Dictionary Metadata { get; set; } = []; /// /// 路径别名定义列表。 /// 例如: "hasAssignments as (IfcObjectDefinition)->HasAssignments->RelatedObjectsType" /// public List Aliases { get; set; } = []; /// /// 实体定义列表。 /// public List EntityDefinitions { get; set; } = []; } /// /// 代表一个规则定义 /// public class Alias { public string Name { get; set; } public string SourceType { get; set; } public string Path { get; set; } public override string ToString() => $"{Name} as ({SourceType}){Path}"; } /// /// 代表一个在 "定义" 块中定义的实体。 /// public class EntityDefinition { /// /// 继承那一行的名称 /// public string Name { get; set; } /// /// 定义后的第一行描述 /// public string Description { get; set; } /// /// 继承自的名称 /// public string InheritsFrom { get; set; } /// /// 新增:专门存放“类型标签”的值列表 /// public List TypeLabels { get; set; } = []; /// /// 类型判断 /// public List Conditions { get; set; } = []; /// /// 约束,每个约束就是一个属性条目 /// public List Constraints { get; set; } = []; public string IfcMap { get; set; } // 来自 "# IFC_MAP = 'IfcElement'" 这样的注释 public override string ToString() => $"Entity: {Name}" + (string.IsNullOrEmpty(InheritsFrom) ? "" : $" inherits {InheritsFrom}"); } /// /// 代表一个在 "约束" 块中定义的规则,即一个属性条目 /// public class Constraint { /// /// 描述约束规则,如:'预制剪力墙 的属性 \"编号\" 应满足值类型约束规则' /// public string Description { get; set; } /// /// 表达式,如:预制剪力墙->任意属性集->任意属性('编号')->属性值[Type]>='STRING' /// public string Expression { get; set; } /// ///用于解析注释中的额外信息,例如: # PropName = '型号规格',key:PropName,Value:型号规格,Key:Range,Value:>=0 /// 固定只有两个,一个是属性名,一个取值范围 /// public Dictionary Properties { get; set; } = []; public string ParameterType { get { if (ValueRange.Contains("实数值")) { return "Number"; } return "Text"; } } public string[] Values { get { if (ValueRange.Contains("值类型")) { return []; } return [.. Regex.Matches(ValueRange, @"\\""([^""]*)\\""").OfType().Select(m => m.Groups[1].Value)]; } } public string PropName => Properties.ContainsKey("PropName") ? Properties["PropName"] : string.Empty; public string ValueRange => Properties.ContainsKey("Range") ? Properties["Range"] : string.Empty; public override string ToString() => $"Constraint: {PropName} => {ValueRange}"; } /// /// 一个静态工具类,用于将MVDLite格式的文本数据解析为结构化的C#对象。 /// public class MvdLiteAssists { private enum ParserState { Idle, // 用于解析元数据和别名 InDefinition, InConstraint } /// /// 不重名属性 /// /// /// public static HashSet GetDistinctProperties(MvdData mvdData) { HashSet properties = []; List definitions = mvdData.EntityDefinitions; foreach (var entity in definitions) { var constraints = entity.Constraints; foreach (var cons in constraints) { if (string.IsNullOrEmpty(cons.PropName) || string.IsNullOrEmpty(cons.Description)) { continue; } var property = $"{cons.PropName},{cons.ParameterType},{cons.ValueRange}"; //var property = new AfcaArchiProperty //{ // DefinitionName = entity.Name, // Name = cons.PropName, // ValueConstraints = cons.Values, // IsChecked = false //}; properties.Add(property); } } return properties; } /// /// 解析包含MVDLite数据的文本字符串。 /// /// 要解析的文本内容。 /// 一个包含所有解析后数据的 MvdData 对象。 public static MvdData Parse(string textContent) { var mvdData = new MvdData(); if (string.IsNullOrWhiteSpace(textContent)) return mvdData; var lines = textContent.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None); ParserState state = ParserState.Idle; EntityDefinition currentEntity = null; Constraint currentConstraint = null; // 用于匹配不同类型行的正则表达式 var metaRegex = new Regex(@"^#\s*([^=]+?)\s*=\s*'(.*)'"); var aliasRegex = new Regex(@"^(\S+)\s+as\s+\((.*?)\)(.*)"); var entityInheritRegex = new Regex(@"^(\S+)\s+继承\s+(\S+)"); var descriptionCommentRegex = new Regex(@"^#\s*'(.*)'"); var ifcMapCommentRegex = new Regex(@"^#\s*IFC_MAP\s*=\s*'(.*)'"); var propCommentRegex = new Regex(@"^#\s*(\w+)\s*=\s*'(.*)'"); // 新增:专门用于匹配“类型标签”的正则表达式 var typeLabelRegex = new Regex(@"^(\S+)->类型标签\s*=\s*(.*)$"); foreach (var line in lines) { var trimmedLine = line.Trim(); if (trimmedLine.StartsWith("定义")) { state = ParserState.InDefinition; currentEntity = new EntityDefinition(); mvdData.EntityDefinitions.Add(currentEntity); continue; } if (trimmedLine.StartsWith("约束")) { state = ParserState.InConstraint; currentConstraint = null; continue; } if (trimmedLine.StartsWith("#BLOCK") || string.IsNullOrWhiteSpace(trimmedLine)) { if (state == ParserState.InConstraint && currentEntity != null && currentConstraint != null && !string.IsNullOrEmpty(currentConstraint.Expression)) { currentEntity.Constraints.Add(currentConstraint); } currentConstraint = null; if (string.IsNullOrWhiteSpace(trimmedLine)) continue; if (trimmedLine.StartsWith("#BLOCK")) { state = ParserState.Idle; currentEntity = null; continue; } } switch (state) { case ParserState.Idle: Match metaMatch = metaRegex.Match(trimmedLine); if (metaMatch.Success) { mvdData.Metadata[metaMatch.Groups[1].Value.Trim()] = metaMatch.Groups[2].Value; break; } Match aliasMatch = aliasRegex.Match(trimmedLine); if (aliasMatch.Success) { mvdData.Aliases.Add(new Alias { Name = aliasMatch.Groups[1].Value, SourceType = aliasMatch.Groups[2].Value, Path = aliasMatch.Groups[3].Value.Trim() }); } break; case ParserState.InDefinition: Match descMatch = descriptionCommentRegex.Match(trimmedLine); if (descMatch.Success) { currentEntity.Description = descMatch.Groups[1].Value; break; } Match ifcMapMatch = ifcMapCommentRegex.Match(trimmedLine); if (ifcMapMatch.Success) { currentEntity.IfcMap = ifcMapMatch.Groups[1].Value; break; } // --- 新增逻辑:优先处理类型标签 --- Match typeLabelMatch = typeLabelRegex.Match(trimmedLine); if (typeLabelMatch.Success) { string allLabelsRaw = typeLabelMatch.Groups[2].Value; // 使用正则表达式从长字符串中提取所有被单引号包裹的值 var labelMatches = Regex.Matches(allLabelsRaw, @"'([^']*)'"); var labels = labelMatches.Cast() .Select(m => m.Groups[1].Value) .ToList(); currentEntity.TypeLabels.AddRange(labels); break; // 处理完毕,跳过此行后续逻辑 } // --- 结束新增逻辑 --- Match entityInheritMatch = entityInheritRegex.Match(trimmedLine); if (entityInheritMatch.Success) { currentEntity.Name = entityInheritMatch.Groups[1].Value; currentEntity.InheritsFrom = entityInheritMatch.Groups[2].Value; } else if (!trimmedLine.StartsWith("#")) { // 其他非注释行、非类型标签行,被视为普通条件 currentEntity.Conditions.Add(trimmedLine); } break; case ParserState.InConstraint: if (trimmedLine.StartsWith("#")) { Match constraintDescMatch = descriptionCommentRegex.Match(trimmedLine); if (constraintDescMatch.Success) { if (currentEntity != null && currentConstraint != null && !string.IsNullOrEmpty(currentConstraint.Expression)) { currentEntity.Constraints.Add(currentConstraint); } currentConstraint = new Constraint { Description = constraintDescMatch.Groups[1].Value }; } else { Match propMatch = propCommentRegex.Match(trimmedLine); if (propMatch.Success) { if (currentConstraint == null) currentConstraint = new Constraint(); currentConstraint.Properties[propMatch.Groups[1].Value] = propMatch.Groups[2].Value; } } } else { if (currentConstraint == null) { currentConstraint = new Constraint(); } currentConstraint.Expression = trimmedLine; if (currentEntity != null) { currentEntity.Constraints.Add(currentConstraint); } currentConstraint = null; } break; } } if (currentEntity != null && currentConstraint != null && !string.IsNullOrEmpty(currentConstraint.Expression)) { currentEntity.Constraints.Add(currentConstraint); } return mvdData; } public static List Lookup(MvdData mvdData, string entityName) { // 查找所有匹配的实体定义 return mvdData.EntityDefinitions .Where(e => e.Name.Equals(entityName, StringComparison.OrdinalIgnoreCase)) .ToList(); } /// /// 查找所有在其类型标签列表中包含指定名称的实体定义。 /// /// 要搜索的数据源。 /// 要查找的类型标签名称。 /// 一个枚举值,指定比较字符串时是否区分大小写。默认为区分大小写。 /// 一个包含所有匹配的实体定义的列表。 public static List FindByTypeLabel( MvdData mvdData, string labelToFind, StringComparison comparisonType = StringComparison.Ordinal) { var allDefinitions = mvdData.EntityDefinitions; // 如果输入为空,则返回一个空列表 if (allDefinitions == null || string.IsNullOrEmpty(labelToFind) || mvdData.EntityDefinitions.Count == 0) { return []; } // 使用 LINQ 进行高效查询: // 遍历所有实体定义(def), // 并在每个实体的 TypeLabels 列表中查找(Any)是否存在一个标签(label) // 与要查找的标签(labelToFind)相等。 return [.. allDefinitions.Where( def => def.TypeLabels.Any(label => label.Equals(labelToFind, comparisonType)))]; } }