Files

379 lines
14 KiB
C#
Raw Permalink Normal View History

2025-09-16 16:06:41 +08:00
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;
/// <summary>
/// 用于保存从MVDLite文本中解析出的结构化数据的类。
/// </summary>
public class MvdData
{
/// <summary>
/// 文件头部的元数据。
/// 例如:# MVDLite_Version = '2.5.0.0'
/// </summary>
public Dictionary<string, string> Metadata { get; set; } = [];
/// <summary>
/// 路径别名定义列表。
/// 例如: "hasAssignments as (IfcObjectDefinition)->HasAssignments->RelatedObjectsType"
/// </summary>
public List<Alias> Aliases { get; set; } = [];
/// <summary>
/// 实体定义列表。
/// </summary>
public List<EntityDefinition> EntityDefinitions { get; set; } = [];
}
/// <summary>
/// 代表一个规则定义
/// </summary>
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}";
}
/// <summary>
/// 代表一个在 "定义" 块中定义的实体。
/// </summary>
public class EntityDefinition
{
/// <summary>
/// 继承那一行的名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 定义后的第一行描述
/// </summary>
public string Description { get; set; }
/// <summary>
/// 继承自的名称
/// </summary>
public string InheritsFrom { get; set; }
/// <summary>
/// 新增:专门存放“类型标签”的值列表
/// </summary>
public List<string> TypeLabels { get; set; } = [];
/// <summary>
/// 类型判断
/// </summary>
public List<string> Conditions { get; set; } = [];
/// <summary>
/// 约束,每个约束就是一个属性条目
/// </summary>
public List<Constraint> Constraints { get; set; } = [];
public string IfcMap { get; set; } // 来自 "# IFC_MAP = 'IfcElement'" 这样的注释
public override string ToString() => $"Entity: {Name}" + (string.IsNullOrEmpty(InheritsFrom) ? "" : $" inherits {InheritsFrom}");
}
/// <summary>
/// 代表一个在 "约束" 块中定义的规则,即一个属性条目
/// </summary>
public class Constraint
{
/// <summary>
/// 描述约束规则,如:'预制剪力墙 的属性 \"编号\" 应满足值类型约束规则'
/// </summary>
public string Description { get; set; }
/// <summary>
/// 表达式,如:预制剪力墙->任意属性集->任意属性('编号')->属性值[Type]>='STRING'
/// </summary>
public string Expression { get; set; }
/// <summary>
///用于解析注释中的额外信息,例如: # PropName = '型号规格'keyPropNameValue型号规格KeyRangeValue>=0
/// 固定只有两个,一个是属性名,一个取值范围
/// </summary>
public Dictionary<string, string> 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<Match>().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}";
}
/// <summary>
/// 一个静态工具类用于将MVDLite格式的文本数据解析为结构化的C#对象。
/// </summary>
public class MvdLiteAssists
{
private enum ParserState
{
Idle, // 用于解析元数据和别名
InDefinition,
InConstraint
}
/// <summary>
/// 不重名属性
/// </summary>
/// <param name="mvdData"></param>
/// <returns></returns>
public static HashSet<string> GetDistinctProperties(MvdData mvdData)
{
HashSet<string> properties = [];
List<EntityDefinition> 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;
}
/// <summary>
/// 解析包含MVDLite数据的文本字符串。
/// </summary>
/// <param name="textContent">要解析的文本内容。</param>
/// <returns>一个包含所有解析后数据的 MvdData 对象。</returns>
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<Match>()
.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<EntityDefinition> Lookup(MvdData mvdData, string entityName)
{
// 查找所有匹配的实体定义
return mvdData.EntityDefinitions
.Where(e => e.Name.Equals(entityName, StringComparison.OrdinalIgnoreCase))
.ToList();
}
/// <summary>
/// 查找所有在其类型标签列表中包含指定名称的实体定义。
/// </summary>
/// <param name="mvdData">要搜索的数据源。</param>
/// <param name="labelToFind">要查找的类型标签名称。</param>
/// <param name="comparisonType">一个枚举值,指定比较字符串时是否区分大小写。默认为区分大小写。</param>
/// <returns>一个包含所有匹配的实体定义的列表。</returns>
public static List<EntityDefinition> 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)))];
}
}