2026-07-02 15:53:30 +08:00
|
|
|
|
# Qfod 解析器
|
|
|
|
|
|
|
|
|
|
|
|
> 所属模块:[解析器设计](./概览.md)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 1. 日志格式
|
|
|
|
|
|
|
|
|
|
|
|
**格式:** `X#:Q A->B C D E`
|
|
|
|
|
|
|
|
|
|
|
|
**示例:** `0#:Q 1->25 45.5 20.5 2`
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 2. 字段定义
|
|
|
|
|
|
|
|
|
|
|
|
| 字段标识 | 字段名称 | 数据类型 | 取值范围 | 说明 |
|
|
|
|
|
|
|----------|----------|----------|----------|------|
|
|
|
|
|
|
| X | ChargerIndex | byte | 0, 1 | 充电器索引 |
|
|
|
|
|
|
| A | CoilIndex | byte | 0, 1, 2 | 线圈索引 |
|
|
|
|
|
|
| B | DeltaQ | int | - | Q值变化量(ΔQ = CurrentQ - RawQ) |
|
|
|
|
|
|
| C | CurrentQ | float | - | 当前实时Q值 |
|
|
|
|
|
|
| D | RawQ | float | - | 原始Q值 |
|
|
|
|
|
|
| E | FodType | byte | 见Table 2 | 异物类型编码 |
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 3. 正则表达式
|
|
|
|
|
|
|
|
|
|
|
|
```csharp
|
|
|
|
|
|
// Parsers/QfodParser.cs
|
|
|
|
|
|
private static readonly Regex QfodPattern = new(
|
|
|
|
|
|
@"^(\d)#:Q\s+(\d+)->(-?\d+)\s+([-\d.]+)\s+([-\d.]+)\s+(\d+)$",
|
|
|
|
|
|
RegexOptions.Compiled
|
|
|
|
|
|
);
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**捕获组映射:**
|
|
|
|
|
|
|
|
|
|
|
|
| 捕获组 | 字段 | 类型转换 |
|
|
|
|
|
|
|--------|------|----------|
|
|
|
|
|
|
| Group 1 | ChargerIndex | byte.Parse() |
|
|
|
|
|
|
| Group 2 | CoilIndex | byte.Parse() |
|
|
|
|
|
|
| Group 3 | DeltaQ | int.Parse() |
|
|
|
|
|
|
| Group 4 | CurrentQ | float.Parse() |
|
|
|
|
|
|
| Group 5 | RawQ | float.Parse() |
|
|
|
|
|
|
| Group 6 | FodType | byte.Parse() |
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 4. 解析器实现
|
|
|
|
|
|
|
|
|
|
|
|
```csharp
|
|
|
|
|
|
// Parsers/QfodParser.cs
|
|
|
|
|
|
using System.Text.RegularExpressions;
|
|
|
|
|
|
using WCTDataMiner.Models;
|
|
|
|
|
|
|
|
|
|
|
|
namespace WCTDataMiner.Parsers;
|
|
|
|
|
|
|
|
|
|
|
|
public class QfodParser : IParser<QfodRecord>
|
|
|
|
|
|
{
|
|
|
|
|
|
private static readonly Regex QfodPattern = new(
|
|
|
|
|
|
@"^(\d)#:Q\s+(\d+)->(-?\d+)\s+([-\d.]+)\s+([-\d.]+)\s+(\d+)$",
|
|
|
|
|
|
RegexOptions.Compiled
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
public bool CanParse(string line) => QfodPattern.IsMatch(line);
|
|
|
|
|
|
|
2026-07-02 18:13:56 +08:00
|
|
|
|
public ParseResult<QfodRecord> Parse(string line, Guid scenarioId)
|
2026-07-02 15:53:30 +08:00
|
|
|
|
{
|
|
|
|
|
|
var match = QfodPattern.Match(line);
|
|
|
|
|
|
if (!match.Success)
|
|
|
|
|
|
{
|
|
|
|
|
|
return ParseResult<QfodRecord>.Failure(
|
|
|
|
|
|
"FORMAT_MISMATCH",
|
|
|
|
|
|
"Line does not match Qfod pattern"
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
var record = new QfodRecord
|
|
|
|
|
|
{
|
2026-07-02 18:13:56 +08:00
|
|
|
|
ScenarioId = scenarioId,
|
2026-07-02 15:53:30 +08:00
|
|
|
|
ChargerIndex = byte.Parse(match.Groups[1].Value),
|
|
|
|
|
|
CoilIndex = byte.Parse(match.Groups[2].Value),
|
|
|
|
|
|
DeltaQ = int.Parse(match.Groups[3].Value),
|
|
|
|
|
|
CurrentQ = float.Parse(match.Groups[4].Value),
|
|
|
|
|
|
RawQ = float.Parse(match.Groups[5].Value),
|
|
|
|
|
|
FodType = byte.Parse(match.Groups[6].Value)
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
return ParseResult<QfodRecord>.Success(record);
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
return ParseResult<QfodRecord>.Failure(
|
|
|
|
|
|
"TYPE_CONVERSION",
|
|
|
|
|
|
$"Failed to convert field: {ex.Message}"
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 5. 检测通道组合
|
|
|
|
|
|
|
|
|
|
|
|
`ChargerIndex + CoilIndex` 组合唯一标识一个检测通道:
|
|
|
|
|
|
|
|
|
|
|
|
| ChargerIndex | CoilIndex | 检测通道 |
|
|
|
|
|
|
|--------------|-----------|----------|
|
|
|
|
|
|
| 0 | 0 | 充电器0 线圈0 |
|
|
|
|
|
|
| 0 | 1 | 充电器0 线圈1 |
|
|
|
|
|
|
| 0 | 2 | 充电器0 线圈2 |
|
|
|
|
|
|
| 1 | 0 | 充电器1 线圈0 |
|
|
|
|
|
|
| 1 | 1 | 充电器1 线圈1 |
|
|
|
|
|
|
| 1 | 2 | 充电器1 线圈2 |
|