bugfix: 修复已知bug
This commit is contained in:
@@ -4,49 +4,113 @@ using WCTDataMiner.Core.Models;
|
||||
namespace WCTDataMiner.Core.Parsers;
|
||||
|
||||
/// <summary>
|
||||
/// Ploss FOD日志解析器
|
||||
/// 格式: FOD-> (1) X X X (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) (12) (13)
|
||||
/// 示例: FOD-> 4 2 1 127 10690 12013 35377 9904 1213 -2882 750 0 0 1 500 1
|
||||
/// Ploss FOD日志解析器 - 支持两行格式
|
||||
/// 第一行: pow_loss = 3053, delta_p = 1950
|
||||
/// 第二行: FOD-> (1) (2) ... (16)
|
||||
/// 同时兼容旧的单行格式
|
||||
/// </summary>
|
||||
public class PlossParser : IParser<PlossRecord>
|
||||
{
|
||||
// 格式说明有3个X(忽略字段),正则需要3个 \d+ 来匹配
|
||||
private static readonly Regex PlossPattern = new(
|
||||
@"^FOD->\s+(\d+)\s+\d+\s+\d+\s+\d+\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(-?\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)$",
|
||||
// 第一行正则:pow_loss = 3053, delta_p = 1950
|
||||
private static readonly Regex HeaderPattern = new(
|
||||
@"^pow_loss\s*=\s*(\d+),\s*delta_p\s*=\s*(\d+)$",
|
||||
RegexOptions.Compiled
|
||||
);
|
||||
|
||||
public bool CanParse(string line) => PlossPattern.IsMatch(line);
|
||||
// 第二行正则:FOD-> 后跟16个数字(均支持负数)
|
||||
private static readonly Regex FodPattern = new(
|
||||
@"^FOD->\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)$",
|
||||
RegexOptions.Compiled
|
||||
);
|
||||
|
||||
// 旧格式正则(兼容):前3个字段被忽略,所有捕获组支持负数
|
||||
private static readonly Regex LegacyPattern = new(
|
||||
@"^FOD->\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)$",
|
||||
RegexOptions.Compiled
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// 判断是否可以解析该行(任意一行)
|
||||
/// </summary>
|
||||
public bool CanParse(string line) =>
|
||||
HeaderPattern.IsMatch(line) || FodPattern.IsMatch(line) || LegacyPattern.IsMatch(line);
|
||||
|
||||
/// <summary>
|
||||
/// 判断是否为多行记录的起始行(header行)
|
||||
/// </summary>
|
||||
public bool IsMultiLineStart(string line) => HeaderPattern.IsMatch(line);
|
||||
|
||||
/// <summary>
|
||||
/// 单行解析(兼容旧格式)
|
||||
/// </summary>
|
||||
public ParseResult<PlossRecord> Parse(string line, Guid scenarioId)
|
||||
{
|
||||
var match = PlossPattern.Match(line);
|
||||
if (!match.Success)
|
||||
// 尝试匹配旧格式
|
||||
var legacyMatch = LegacyPattern.Match(line);
|
||||
if (legacyMatch.Success)
|
||||
{
|
||||
return ParseResult<PlossRecord>.Failure(
|
||||
"FORMAT_MISMATCH",
|
||||
"Line does not match Ploss pattern"
|
||||
);
|
||||
return ParseLegacyFormat(legacyMatch, scenarioId);
|
||||
}
|
||||
|
||||
// 尝试匹配第二行(新格式)
|
||||
var fodMatch = FodPattern.Match(line);
|
||||
if (fodMatch.Success)
|
||||
{
|
||||
return ParseFodLine(fodMatch, scenarioId);
|
||||
}
|
||||
|
||||
// 尝试匹配第一行
|
||||
var headerMatch = HeaderPattern.Match(line);
|
||||
if (headerMatch.Success)
|
||||
{
|
||||
return ParseHeaderLine(headerMatch, scenarioId);
|
||||
}
|
||||
|
||||
return ParseResult<PlossRecord>.Failure(
|
||||
"FORMAT_MISMATCH",
|
||||
"Line does not match Ploss pattern"
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 多行解析(新两行格式)
|
||||
/// </summary>
|
||||
public ParseResult<PlossRecord>? ParseMultiLine(string[] lines, Guid scenarioId)
|
||||
{
|
||||
if (lines.Length < 2)
|
||||
return null;
|
||||
|
||||
var headerMatch = HeaderPattern.Match(lines[0].Trim());
|
||||
var fodMatch = FodPattern.Match(lines[1].Trim());
|
||||
|
||||
if (!headerMatch.Success || !fodMatch.Success)
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
var record = new PlossRecord
|
||||
{
|
||||
ScenarioId = scenarioId,
|
||||
RxType = byte.Parse(match.Groups[1].Value),
|
||||
RxPower = int.Parse(match.Groups[2].Value),
|
||||
TxPower = int.Parse(match.Groups[3].Value),
|
||||
Vcoil = int.Parse(match.Groups[4].Value),
|
||||
Vin = int.Parse(match.Groups[5].Value),
|
||||
Isns = int.Parse(match.Groups[6].Value),
|
||||
Ploss = int.Parse(match.Groups[7].Value),
|
||||
Threshold = int.Parse(match.Groups[8].Value),
|
||||
TriggerCount = int.Parse(match.Groups[9].Value),
|
||||
FodResult = int.Parse(match.Groups[10].Value),
|
||||
ProtocolType = byte.Parse(match.Groups[11].Value),
|
||||
PwmDuty = int.Parse(match.Groups[12].Value),
|
||||
CoilIndex = byte.Parse(match.Groups[13].Value)
|
||||
// 第一行字段
|
||||
PowLoss = int.Parse(headerMatch.Groups[1].Value),
|
||||
DeltaP = int.Parse(headerMatch.Groups[2].Value),
|
||||
// 第二行字段
|
||||
Field1 = int.Parse(fodMatch.Groups[1].Value),
|
||||
Field2 = int.Parse(fodMatch.Groups[2].Value),
|
||||
Field3 = int.Parse(fodMatch.Groups[3].Value),
|
||||
Field4 = int.Parse(fodMatch.Groups[4].Value),
|
||||
Field5 = int.Parse(fodMatch.Groups[5].Value),
|
||||
Field6 = int.Parse(fodMatch.Groups[6].Value),
|
||||
Field7 = int.Parse(fodMatch.Groups[7].Value),
|
||||
Field8 = int.Parse(fodMatch.Groups[8].Value),
|
||||
Field9 = int.Parse(fodMatch.Groups[9].Value), // 支持负数
|
||||
Field10 = int.Parse(fodMatch.Groups[10].Value),
|
||||
Field11 = int.Parse(fodMatch.Groups[11].Value),
|
||||
Field12 = int.Parse(fodMatch.Groups[12].Value),
|
||||
Field13 = int.Parse(fodMatch.Groups[13].Value),
|
||||
Field14 = int.Parse(fodMatch.Groups[14].Value),
|
||||
Field15 = int.Parse(fodMatch.Groups[15].Value),
|
||||
Field16 = int.Parse(fodMatch.Groups[16].Value)
|
||||
};
|
||||
|
||||
return ParseResult<PlossRecord>.Success(record);
|
||||
@@ -59,4 +123,106 @@ public class PlossParser : IParser<PlossRecord>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private ParseResult<PlossRecord> ParseLegacyFormat(Match match, Guid scenarioId)
|
||||
{
|
||||
// 保持原有逻辑不变,映射到新字段名
|
||||
try
|
||||
{
|
||||
var record = new PlossRecord
|
||||
{
|
||||
ScenarioId = scenarioId,
|
||||
// 旧格式没有第一行字段
|
||||
PowLoss = null,
|
||||
DeltaP = null,
|
||||
// 映射到新字段名
|
||||
Field1 = int.Parse(match.Groups[1].Value), // RxType
|
||||
Field2 = int.Parse(match.Groups[2].Value), // RxPower
|
||||
Field3 = int.Parse(match.Groups[3].Value), // TxPower
|
||||
Field4 = int.Parse(match.Groups[4].Value), // Vcoil
|
||||
Field5 = int.Parse(match.Groups[5].Value), // Vin
|
||||
Field6 = int.Parse(match.Groups[6].Value), // Isns
|
||||
Field7 = int.Parse(match.Groups[7].Value), // Ploss
|
||||
Field8 = int.Parse(match.Groups[8].Value), // Threshold
|
||||
Field9 = int.Parse(match.Groups[9].Value), // TriggerCount
|
||||
Field10 = int.Parse(match.Groups[10].Value), // FodResult
|
||||
Field11 = int.Parse(match.Groups[11].Value), // ProtocolType
|
||||
Field12 = int.Parse(match.Groups[12].Value), // PwmDuty
|
||||
Field13 = int.Parse(match.Groups[13].Value), // CoilIndex
|
||||
// 旧格式没有Field14-16,使用默认值
|
||||
Field14 = 0,
|
||||
Field15 = 0,
|
||||
Field16 = 0
|
||||
};
|
||||
return ParseResult<PlossRecord>.Success(record);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ParseResult<PlossRecord>.Failure(
|
||||
"TYPE_CONVERSION",
|
||||
$"Failed to convert field: {ex.Message}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private ParseResult<PlossRecord> ParseHeaderLine(Match match, Guid scenarioId)
|
||||
{
|
||||
// 单独解析header行,返回部分记录
|
||||
// 实际使用时应通过ParseMultiLine合并
|
||||
try
|
||||
{
|
||||
var record = new PlossRecord
|
||||
{
|
||||
ScenarioId = scenarioId,
|
||||
PowLoss = int.Parse(match.Groups[1].Value),
|
||||
DeltaP = int.Parse(match.Groups[2].Value)
|
||||
};
|
||||
return ParseResult<PlossRecord>.Success(record);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ParseResult<PlossRecord>.Failure(
|
||||
"TYPE_CONVERSION",
|
||||
$"Failed to convert header field: {ex.Message}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private ParseResult<PlossRecord> ParseFodLine(Match match, Guid scenarioId)
|
||||
{
|
||||
// 单独解析FOD行(新格式,无header)
|
||||
try
|
||||
{
|
||||
var record = new PlossRecord
|
||||
{
|
||||
ScenarioId = scenarioId,
|
||||
PowLoss = null,
|
||||
DeltaP = null,
|
||||
Field1 = byte.Parse(match.Groups[1].Value),
|
||||
Field2 = int.Parse(match.Groups[2].Value),
|
||||
Field3 = int.Parse(match.Groups[3].Value),
|
||||
Field4 = int.Parse(match.Groups[4].Value),
|
||||
Field5 = int.Parse(match.Groups[5].Value),
|
||||
Field6 = int.Parse(match.Groups[6].Value),
|
||||
Field7 = int.Parse(match.Groups[7].Value),
|
||||
Field8 = int.Parse(match.Groups[8].Value),
|
||||
Field9 = int.Parse(match.Groups[9].Value),
|
||||
Field10 = int.Parse(match.Groups[10].Value),
|
||||
Field11 = int.Parse(match.Groups[11].Value),
|
||||
Field12 = int.Parse(match.Groups[12].Value),
|
||||
Field13 = int.Parse(match.Groups[13].Value),
|
||||
Field14 = int.Parse(match.Groups[14].Value),
|
||||
Field15 = int.Parse(match.Groups[15].Value),
|
||||
Field16 = int.Parse(match.Groups[16].Value)
|
||||
};
|
||||
return ParseResult<PlossRecord>.Success(record);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ParseResult<PlossRecord>.Failure(
|
||||
"TYPE_CONVERSION",
|
||||
$"Failed to convert FOD field: {ex.Message}"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user