LDF文件详解
一、摘要
1.描述
本文主要描述的是汽车行业中LDF文件的格式,如何去解析它,如何通过文本编辑器去修改它,了解LDF文件之前如果不懂LDF的请去查看我之前的博客。
2.关键字
LDF,LDF解析,LDF数据库,LDF文件,C#解析LDF文件。
二、为什么要了解LDF文件
LDF文件在汽车行业应用十分广泛,如果编辑LDF文件我们都使用Vector工具DF Explorer Pro或者LDFEditor去编辑,那效率将会是十分的低下,当我们了解了LDF文件的构成后,我们可以通过其他方式进行解析,可以大大的提高工作的效率,我们可以通过记事本或者其他工具打开LDF文件。
三、LDF文件构成
1.版本
关键字:LIN_protocol_version
格式:LIN_protocol_version = “version”;
格式中的version就是版本信息,版本信息可以为空,但是不能省略""符。
例如:LIN_protocol_version = “2.1”;代表版本号为V2.1。
2.波特率
关键字:LIN_speed
格式:LIN_speed = baudrate;
格式中的baudrate就是波特率。
例如:LIN_speed = 19.2 kbps;;代表波特率为19200。
3.节点信息
关键字:Nodes
格式:Nodes {
Master: name1 jitter ms, timebase ms ;
Slaves: name2,name3…;
}
name1:主节点名称。
jitter:偏移是指一帧报文实际开始发送的时刻与帧时隙起点的时间差。
timebase:时间基数
name2,name3…:代表接收节点名称。
例如:Nodes {
Master: GW_BCM, 1 ms, 0 ms ;
Slaves: LIN_RLS,Tellus_Node;
}
代表主节点名称为BCM,偏移为1ms,时间基数为0ms,从节点名称为LIN_RLS和Tellus_Node。
4.信号信息
关键字:Signals
格式:Signals {
Signal_Name: Bit_Length, Signal_Init_Value, name1, name2… ;
…;
}
Signal_Name:信号名称,命名规则和C语言变量相同。
Bit_Length:信号的长度,范围为1-64。
Signal_Init_Value:信号初始值。
name1,name2…:代表接收节点名称。
例如:Signals {
BCM_WiperRunning: 1, 0, GW_BCM, LIN_RLS ;
RLS_MessageCounter: 4, 0, LIN_RLS, GW_BCM;
}
代表信号名称为BCM_WiperRunning的长度为1,初始值为0,接收节点有GW_BCM, LIN_RLS;
信号名称为RLS_MessageCounter的长度为4,初始值为0,接收节点有LIN_RLS, GW_BCM;
5.诊断信号信息
关键字:Diagnostic_signals
格式:Diagnostic_signals{
Signal_Name: Bit_Length, Signal_Init_Value ;
…;
}
Msg_ID:报文标识符,十进制表示。
Msg_Name:报文名称,命名规则和C语言变量相同。
Msg_Length :报文长度,长度范围为0-8。
例如:Diagnostic_signals{
MasterReqB0: 8, 0 ;
MasterReqB1: 8, 0 ;
MasterReqB2: 8, 0 ;
MasterReqB3: 8, 0 ;
MasterReqB4: 8, 0 ;
MasterReqB5: 8, 0 ;
MasterReqB6: 8, 0 ;
MasterReqB7: 8, 0 ;
SlaveRespB0: 8, 0 ;
SlaveRespB1: 8, 0 ;
SlaveRespB2: 8, 0 ;
SlaveRespB3: 8, 0 ;
SlaveRespB4: 8, 0 ;
SlaveRespB5: 8, 0 ;
SlaveRespB6: 8, 0 ;
SlaveRespB7: 8, 0 ;
}
诊断报文一般自动生成的格式基本不变,也可以做一定名字调整等。
6.报文消息
关键字:Frames
格式:Frames {
Msg_Name: Msg_ID, Msg_Transmitter, Msg_Length {
Signal_Name, Start_Bit;
…;
};
…;
}
Msg_Name:报文名称,命名规则和C语言变量相同。
Msg_ID:报文标识符,十进制或者十六进制表示。
Msg_Transmitter:发送节点。
Msg_Length :报文长度,长度范围为0-8。
Signal_Name:信号名称,命名规则和C语言变量相同。
Start_Bit:信号的起始位,范围为0-63。
例如:Frames {
BCM_data: 21, GW_BCM, 8{
BCM_WiperRunning, 23;
}
RLS_data: 13, LIN_RLS, 8{
RLS_MessageCounter, 0;
}
}
代表报文名称BCM_data的ID为0x15,长度为8,发送节点为GW_BCM,包含信号名称为BCM_WiperRunning,该信号起始位为23;
报文名称RLS_data的ID为0x0D,长度为8,发送节点为LIN_RLS,包含信号名称为RLS_MessageCounter,该信号起始位为0;
7.诊断报文消息
关键字:Diagnostic_frames
格式:Diagnostic_frames {
MasterReq: Msg_ID{
Signal_Name, Start_Bit;
…;
};
SlaveResp: Msg_ID{
Signal_Name, Start_Bit;
…;
};
}
Msg_ID:报文标识符,十进制或者十六进制表示。
Msg_Length :报文长度,长度范围为0-8。
Signal_Name:信号名称,命名规则和C语言变量相同。
Start_Bit:信号的起始位,范围为0-63。
例如:Diagnostic_frames {
MasterReq: 0x3c {
MasterReqB0, 0;
MasterReqB1, 8;
MasterReqB2, 16;
MasterReqB3, 24
MasterReqB4, 32;
MasterReqB5, 40;
MasterReqB6, 48;
MasterReqB7, 56;
}
SlaveResp: 0x3d {
SlaveRespB0, 0;
SlaveRespB1, 8;
SlaveRespB2, 16;
SlaveRespB3, 24
SlaveRespB4, 32;
SlaveRespB5, 40;
SlaveRespB6, 48;
SlaveRespB7, 56;
}
}
8.从节点信息
- 关键字:Node_attributes
格式:BA_DEF_ Object AttributeName ValueType Min Max;”
Object:注解的对象类型,可以是节点“BU_”、报文“BO_”、消息”SG_”、网络节点” ”(用空格表示)。
AttributeName: 自定义属性名称,命名规则和C语言变量相同。
ValueType:属性值的类型,可以是整型、字符串、浮点型、枚举类型等。
Min:属性值的最小值(字符串类型没有此项)。
Min:属性值的最大值(字符串类型没有此项)。
例如:BA_DEF_ “ECU” STRING ;代表自定义网络节点属性名称为ECU,类型为字符串型。
BA_DEF_ BO_ “MsgCycleTime” INT 0 1000;代表自定义报文属性名称为MsgCycleTime,类型为整型,取值范围为0-1000。
9.调度表
- 关键字:Node_attributes
格式:BA_DEF_ Object AttributeName ValueType Min Max;”
Object:注解的对象类型,可以是节点“BU_”、报文“BO_”、消息”SG_”、网络节点” ”(用空格表示)。
AttributeName: 自定义属性名称,命名规则和C语言变量相同。
ValueType:属性值的类型,可以是整型、字符串、浮点型、枚举类型等。
Min:属性值的最小值(字符串类型没有此项)。
Min:属性值的最大值(字符串类型没有此项)。
例如:BA_DEF_ “ECU” STRING ;代表自定义网络节点属性名称为ECU,类型为字符串型。
BA_DEF_ BO_ “MsgCycleTime” INT 0 1000;代表自定义报文属性名称为MsgCycleTime,类型为整型,取值范围为0-1000。
10.描述信息
关键字:Signal_encoding_types
格式:Signal_encoding_types {
Signal_Encoding{
physical_value, Min, Max, Factor, Offset,“Unit” ;
logical_value, N, “DefineN;
…;
};
…;
}
Signal_Encoding:信号描述定义名称,命名规则和C语言变量相同。
N:定义的数值表内容。
Min:属性值的最小值(十进制)。
Min:属性值的最大值(十进制)。
Factor:精度。
Offset:偏移量,Factor和Offset这两个值于该信号的原始值与物理值之间的转换,转换如下:物理值=原始值*因子+偏移量。
DefineN:数值表内容对应该信号的有效值分别用什么符号表示。
Unit:信号的单位,为字符串类型,可以省略,省略时“,”也要省略。
例如:Signal_encoding_types{
BCM_AMP_Driver_Encoding {
physical_value, 0, 7, 1, 0 ;
logical_value, 0, “No input” ;
logical_value, 1, “Manual Up” ;
logical_value, 2, “Manual Down” ;
}
}
代表描述信号名称为BCM_AMP_Driver_Encoding 的最小值为0,最大值为7,精度为1,偏移量为0,定义0x00表示为"No input" ,0x01表示为"Manual Up" ,0x02表示为"Manual Down" 。
11.信号描述关联
关键字:Signal_representation
格式:Signal_representation {
Signal_Encoding: Signal_Name1, Signal_Name2…;
…
}
Signal_Encoding:信号描述定义名称,命名规则和C语言变量相同。
Signal_Name1,Signal_Name2…:信号定义名称,命名规则和C语言变量相同。
例如:Signal_representation {
BCM_AMP_Driver_Encoding: BCM_AMP_Driver ;
BCM_DRV_SWITCH_COOL_Encoding: BCM_DRV_SWITCH_COOL ;
}
代表信号名称为BCM_AMP_Driver 的信号定义是BCM_AMP_Driver_Encoding的内容;
BCM_DRV_SWITCH_COOL_Encoding的信号定义是BCM_DRV_SWITCH_COOL 的内容。
四、LDF文件解析
通过以上描述,我相信各位对LDF文件的结构有一定的了解,但是我们如何去解析呢,很多人第一时间想到的应该是按行解析,其实LDF文件有许多容错处理,单纯按行解析我们会错过许多细节部分,例如下图其实也没有出错,如果按行解析的话报文就解析不到了。还有很多类似的容错处理在里面,所以单纯按行解析是不行的,并且有的时候也是不能通过空格来分开数据的,比如带有“”的前后是可以不追加空格的。
经过好久的挣扎,查询资料,终于在一个博客的找到了一种解析的方式,通过正则表达式去解析,当然他其实是按行解析,其实会丢掉一些数据,我将方法进行了一些简单的优化,先读取整个文件到字符串,把多行空格转换成一行空格,然后把换行符转换成空格符,然后进行查找,然后按照标准进行拆分。我这边解析的主要使用的C#语言,因为C#语言对字符串有友好的操作,我将部分代码粘贴如下,方便大家参考学习。
1.解析版本
/**********************************************/
///<summary>
///Name :AnalysisVersion
///Author :WangHu
///Function:***
///Version :V1.0.0
///Data :2022.5.20
///</summary>
/**********************************************/
private static bool AnalysisVersion(MsgInfo_Type msgInfo, string data)
{
string pattern = "LIN_protocol_version([ ]*)(=)([ ]*)\"((([^\"\\s])|([\\s\\u4e00-\\u9fa5]))*)\"([ ]*);";
MatchCollection matchs = Regex.Matches(data, pattern);
foreach (Match match in matchs)
{
if (matchs.Count == 1)
{
string[] array = match.Value.Split(new string[] { @"""" }, StringSplitOptions.RemoveEmptyEntries);
if (array.Length >= 2) { msgInfo.version = array[1]; }
return true;
}
}
return true;
}
2.解析节点信息
/**********************************************/
///<summary>
///Name :AnalysisNodes
///Author :WangHu
///Function:***
///Version :V1.0.0
///Data :2022.5.20
///</summary>
/**********************************************/
private static bool AnalysisNodes(MsgInfo_Type msgInfo, string data)
{
string pattern = "(Nodes[ ]*){[^{}]*}";
foreach (Match match in Regex.Matches(data, pattern))
{
string masterPattern = "(Master[ ]*):([ ]*\\w+[ ]*),([ ]*(\\.|\\w|[ ])+[ ]*),([ ]*(\\.|\\w|[ ])+[ ]*);";
foreach (Match masterMatch in Regex.Matches(match.Value, masterPattern))
{
string[] array = masterMatch.Value.Split(new string[] { " ", ":", ",", ";" }, StringSplitOptions.RemoveEmptyEntries);
msgInfo.master = array[1];
}
string slavesPattern = "(Slaves[ ]*):([ ]*\\w+[ ]*)(,[ ]*\\w+[ ]*)*;";
foreach (Match slavesMatch in Regex.Matches(match.Value, slavesPattern))
{
string[] array = slavesMatch.Value.Split(new string[] { " ", ":", ",", ";" }, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < array.Length - 1; i++) { msgInfo.slaves.Add(array[i + 1]); }
}
}
return true;
}
3.解析调度表
/**********************************************/
///<summary>
///Name :AnalysisScheduleTables
///Author :WangHu
///Function:***
///Version :V1.0.0
///Data :2022.5.20
///</summary>
/**********************************************/
private static bool AnalysisScheduleTables(MsgInfo_Type msgInfo, string data)
{
string pattern = "(Schedule_tables[ ]*){(([^{}]*{[^{}]*})*)[ ]*}";
foreach (Match match in Regex.Matches(data, pattern))
{
string eachPattern = "(\\w+[ ]*){((([ ]*\\w+[ ]+)delay([ ]+(\\d)+[ ]*(\\w)+[ ]*;[ ]*)))*}";
foreach (Match eachMatch in Regex.Matches(match.Value, eachPattern))
{
string[] array = eachMatch.Value.Split(new string[] { " ", "{", "}", ";", "delay" }, StringSplitOptions.RemoveEmptyEntries);
ScheduleInfoModel schedule = new ScheduleInfoModel { Name = array[0] };
for (int i = 0; i < array.Length / 3; i++) { schedule.SlotInfos.Add(new SlotInfoModel() { Name = array[(3 * i) + 1], Delay = CommonLib.ToInt(array[(3 * i) + 2]) }); }
msgInfo.schedules.Add(schedule);
}
}
return true;
}
4.解析报文消息
/**********************************************/
///<summary>
///Name :AnalysisFrames
///Author :WangHu
///Function:***
///Version :V1.0.0
///Data :2022.5.20
///</summary>
/**********************************************/
private static bool AnalysisFrames(List<Message_Type> messages, string data)
{
string pattern = "(Frames[ ]*){(([^{}]*{[^{}]*})*)[ ]*}";
foreach (Match match in Regex.Matches(data, pattern))
{
string eachPattern = "(\\w+[ ]*):([ ]*\\w+[ ]*),([ ]*\\w+[ ]*),([ ]*\\d+[ ]*){(([ ]*)|(((([ ]*\\w+[ ]*),([ ]*\\d+[ ]*);[ ]*))+))}";
foreach (Match eachMatch in Regex.Matches(match.Value, eachPattern))
{
Message_Type message = null;
string messagePattern = "(\\w+[ ]*):([ ]*\\w+[ ]*),([ ]*\\w+[ ]*),([ ]*\\d+[ ]*)";
foreach (Match messageMatch in Regex.Matches(eachMatch.Value, messagePattern))
{
string[] array = messageMatch.Value.Split(new string[] { " ", ",", ":" }, StringSplitOptions.RemoveEmptyEntries);
uint? id = CommonLib.ToDec(array[1]);
if (id == null) { continue; }
message = FindMessage(messages, (uint)id);
if (message == null)
{
message = new Message_Type();
messages.Add(message);
}
message.name = CommonLib.ToVar(array[0]);
message.id = id;
message.transmitter = CommonLib.ToStr(array[2]);
message.length = CommonLib.ToInt(array[3]);
message.sendType = SendTypeEnum.UF.ToString();
message.checksumMode = ChecksumModeEnum.ENHANCED;
}
string signalPattern = "(\\w+[ ]*),([ ]*\\d+[ ]*);";
foreach (Match signalMatch in Regex.Matches(eachMatch.Value, signalPattern))
{
string[] array = signalMatch.Value.Split(new string[] { " ", ",", ";" }, StringSplitOptions.RemoveEmptyEntries);
message.signals.Add(new Signal_Type
{
name = CommonLib.ToStr(array[0]),
startBit = CommonLib.ToInt(array[1]),
byteOrder = ByteOrderEnum.INTEL,
dataType = DataTypeEnum.UNSIGNED,
factor = 1.0,
offset = 0.0
});
}
}
}
return true;
}
5.解析诊断报文消息
/**********************************************/
///<summary>
///Name :AnalysisDiagnosticFrames
///Author :WangHu
///Function:***
///Version :V1.0.0
///Data :2022.5.20
///</summary>
/**********************************************/
private static bool AnalysisDiagnosticFrames(List<Message_Type> messages, string data)
{
string pattern = "(Diagnostic_frames[ ]*){(([^{}]*{[^{}]*})*)[ ]*}";
foreach (Match match in Regex.Matches(data, pattern))
{
string eachPattern = "(\\w+[ ]*):([ ]*\\w+[ ]*){((([ ]*\\w+[ ]*),([ ]*\\d+[ ]*);[ ]*)*)}";
foreach (Match eachMatch in Regex.Matches(match.Value, eachPattern))
{
Message_Type message = null;
string messagePattern = "(\\w+[ ]*):([ ]*\\w+)";
foreach (Match messageMatch in Regex.Matches(eachMatch.Value, messagePattern))
{
string[] array = messageMatch.Value.Split(new string[] { " ", ":" }, StringSplitOptions.RemoveEmptyEntries);
uint? id = CommonLib.ToDec(array[1]);
if (id == null) { continue; }
message = FindMessage(messages, (uint)id);
if (message == null)
{
message = new Message_Type();
messages.Add(message);
}
message.name = CommonLib.ToVar(array[0]);
message.id = id;
message.transmitter = null;
message.length = 8;
message.sendType = SendTypeEnum.DF.ToString();
message.checksumMode = ChecksumModeEnum.CLASSIC;
}
string signalPattern = "(\\w+[ ]*),([ ]*\\d+[ ]*);";
foreach (Match signalMatch in Regex.Matches(eachMatch.Value, signalPattern))
{
string[] array = signalMatch.Value.Split(new string[] { " ", ",", ";" }, StringSplitOptions.RemoveEmptyEntries);
message.signals.Add(new Signal_Type
{
name = CommonLib.ToStr(array[0]),
startBit = CommonLib.ToInt(array[1]),
byteOrder = ByteOrderEnum.INTEL,
dataType = DataTypeEnum.UNSIGNED,
factor = 1.0,
offset = 0.0
});
}
}
}
return true;
}
6.解析信号信息
/**********************************************/
///<summary>
///Name :AnalysisSignals
///Author :WangHu
///Function:***
///Version :V1.0.0
///Data :2022.5.20
///</summary>
/**********************************************/
private static bool AnalysisSignals(List<Message_Type> messages, string data)
{
string pattern = "(Signals[ ]*){[^{}]*}";
foreach (Match match in Regex.Matches(data, pattern))
{
string signalPattern = "(\\w+[ ]*):([ ]*\\d+[ ]*),([ ]*([0][x])?\\d+[ ]*),([ ]*\\w+[ ]*(,[ ]*\\w+[ ]*)*);";
foreach (Match signalMatch in Regex.Matches(match.Value, signalPattern))
{
string[] array = signalMatch.Value.Split(new string[] { " ", ":", ",", ";" }, StringSplitOptions.RemoveEmptyEntries);
string signalName = CommonLib.ToStr(array[0]);
foreach (Message_Type message in messages)
{
foreach (Signal_Type signal in message.signals)
{
if (signal.name == signalName)
{
signal.length = CommonLib.ToInt(array[1]);
signal.initValue = (int?)CommonLib.ToDec(array[2]);
for (int i = 0; i < array.Length - 4; i++) { signal.receivers.Add(CommonLib.ToStr(array[i + 4])); }
}
}
}
}
}
return true;
}
7.解析诊断信号信息
/**********************************************/
///<summary>
///Name :AnalysisDiagnosticSignals
///Author :WangHu
///Function:***
///Version :V1.0.0
///Data :2022.5.20
///</summary>
/**********************************************/
private static bool AnalysisDiagnosticSignals(List<Message_Type> messages, string data)
{
string pattern = "(Diagnostic_signals[ ]*){[^{}]*}";
foreach (Match match in Regex.Matches(data, pattern))
{
string signalPattern = "(\\w+[ ]*):([ ]*\\d+[ ]*),([ ]*([0][x])?\\d+[ ]*);";
foreach (Match signalMatch in Regex.Matches(match.Value, signalPattern))
{
string[] array = signalMatch.Value.Split(new string[] { " ", ":", ",", ";" }, StringSplitOptions.RemoveEmptyEntries);
string signalName = CommonLib.ToStr(array[0]);
foreach (Message_Type message in messages)
{
foreach (Signal_Type signal in message.signals)
{
if (signal.name == signalName)
{
signal.length = CommonLib.ToInt(array[1]);
signal.initValue = (int?)CommonLib.ToDec(array[2]);
}
}
}
}
}
return true;
}
8.解析信号描述关联
private static bool AnalysisSignalRepresentation(List<Message_Type> messages, string data)
{
string pattern = "(Signal_representation[ ]*){[^{}]*}";
foreach (Match match in Regex.Matches(data, pattern))
{
string signalPattern = "([ ]*\\w+[ ]*):([ ]*\\w+[ ]*(,[ ]*\\w+[ ]*)*);";
foreach (Match signalMatch in Regex.Matches(match.Value, signalPattern))
{
string[] array = signalMatch.Value.Split(new string[] { " ", ",", ":", ";" }, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < array.Length - 1; i++)
{
string signalName = CommonLib.ToStr(array[i + 1]);
foreach (Message_Type message in messages)
{
foreach (Signal_Type signal in message.signals)
{
if (signal.name == signalName)
{
signal.encodingName = CommonLib.ToVar(array[0]);
}
}
}
}
}
}
return true;
}
9.解析描述信息
/**********************************************/
///<summary>
///Name :AnalysisSignalEncodingTypes
///Author :WangHu
///Function:***
///Version :V1.0.0
///Data :2022.5.20
///</summary>
/**********************************************/
private static bool AnalysisSignalEncodingTypes(List<Message_Type> messages, string data)
{
string pattern = "(Signal_encoding_types[ ]*){(([^{}]*{[^{}]*})*)[ ]*}";
foreach (Match match in Regex.Matches(data, pattern))
{
string eachPattern = "(\\w+[ ]*){((([ ]*physical_value[ ]*),([ ]*\\w+[ ]*),([ ]*\\w+[ ]*),((([ ]+)|)(-?\\d+(\\.\\d+)?)(([ ]+)|)),((([ ]+)|)(-?\\d+(\\.\\d+)?)(([ ]+)|))((,([ ]*)\"((([^\"\\s])|([\\s\\u4e00-\\u9fa5]))*)\")|)[ ]*;)+|[ ]*)((([ ]*logical_value[ ]*),([ ]*\\d+[ ]*),([ ]*\"((([^\"\\s])|([\\s\\u4e00-\\u9fa5]))*)\")[ ]*;[ ]*)+|[ ]*)}";
foreach (Match eachMatch in Regex.Matches(match.Value, eachPattern))
{
string[] array = eachMatch.Value.Split(new string[] { " ", "{" }, StringSplitOptions.RemoveEmptyEntries);
string encodingName = CommonLib.ToVar(array[0]);
foreach (Message_Type message in messages)
{
foreach (Signal_Type signal in message.signals)
{
if (signal.encodingName == encodingName)
{
try
{
string physicalPattern = "(physical_value[ ]*),([ ]*\\w+[ ]*),([ ]*\\w+[ ]*),((([ ]+)|)(-?\\d+(\\.\\d+)?)(([ ]+)|)),((([ ]+)|)(-?\\d+(\\.\\d+)?)(([ ]+)|))((,([ ]*)\"((([^\"\\s])|([\\s\\u4e00-\\u9fa5]))*)\")|)[ ]*;";
foreach (Match physicalMatch in Regex.Matches(eachMatch.Value, physicalPattern))
{
string[] array1 = physicalMatch.Value.Replace(";", "").Split(new string[] { @"""" }, StringSplitOptions.None);
string[] array2 = array1[0].Split(new string[] { " ", "," }, StringSplitOptions.RemoveEmptyEntries);
signal.minValue = (int?)CommonLib.ToDec(array2[1]);
signal.maxValue = (int?)CommonLib.ToDec(array2[2]);
signal.factor = CommonLib.ToDouble(array2[3]);
signal.offset = CommonLib.ToDouble(array2[4]);
signal.unit = array1.Length >= 2 ? CommonLib.ToStr(array1[1]) : null;
}
string logicalPattern = "(logical_value[ ]*),([ ]*\\d+[ ]*),([ ]*\"((([^\"\\s])|([\\s\\u4e00-\\u9fa5]))*)\")[ ]*;";
foreach (Match logicalMatch in Regex.Matches(eachMatch.Value, logicalPattern))
{
string[] array1 = logicalMatch.Value.Split(new string[] { @"""" }, StringSplitOptions.None);
string[] array2 = array1[0].Split(new string[] { " ", "," }, StringSplitOptions.RemoveEmptyEntries);
signal.valueDescriptions.Add(new ValueDescriptionInfoModel
{
Value = CommonLib.ToDec(array2[1]),
Name = array1[1]
});
}
}
catch { continue; }
}
}
}
}
}
return true;
}
五、MatrixCreat工具
这儿我只把链接放上,具体使用说明见后续章节。
LDF转Excel;LDF转位定义;Excel转LDF;Excel转位定义:https://download.youkuaiyun.com/download/weixin_44926112/86912538
六、其他
本文主要是讲解LDF文件的结构和如何解析LDF文件,有些地方可能会有描述性的错误,希望看到的朋友及时指出,我会及时更正错误,其他地方有些借鉴的描述,写此文章的目的是为了交流,非商业用途,欢迎私信讨论,感谢大家阅读。