You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何高效解析PDF导出的采购订单字符串至对象变量

采购订单字符串高效解析方案

问题背景

有从PDF导出的固定格式采购订单字符串,示例如下:

1
EA
 2.00 2814-212-D003 0.00 0.00
LONG JACK PAD
Drawing: OPT
Due: 05/19/2023 Requester: NMB
Order: 2843HR-213-703 Seq No: 9002
2
EA
 2.00 2814-212-D003 0.00 0.00
LONG JACK PAD
Drawing: OPT
Due: 05/19/2023 Requester: NMB
Order: 2843HR-214-703 Seq No: 9002
3
EA
 2.00 2814-212-D004 0.00 0.00
SHORT JACK PAD
Drawing: OPT
Due: 05/19/2023 Requester: NMB
Order: 2843HR-213-703 Seq No: 9003
4
EA
 2.00 2814-212-D004 0.00 0.00
SHORT JACK PAD
Drawing: OPT
Due: 05/19/2023 Requester: NMB
Order: 2843HR-214-703 Seq No: 9003

需要提取每个条目的行号、数量、零件号、描述、绘图来源、到期日,存入自定义对象后导入Excel。当前用Substring实现逻辑混乱,求更高效的解析方式。

高效解析方案

方法1:按行分割+分组解析(直观可靠)

每个条目固定占7行,先把文本按行拆分,过滤空行后每7行作为一组提取数据:

首先定义自定义对象:

public class PurchaseOrderItem
{
    public int LineNumber { get; set; }
    public decimal Quantity { get; set; }
    public string PartNumber { get; set; }
    public string Description { get; set; }
    public string DrawingSource { get; set; }
    public DateTime DueDate { get; set; }
}

解析代码:

string rawText = richTextBox1.Text;
// 拆分行并过滤空行/纯空白行
var lines = rawText.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries)
                   .Where(line => !string.IsNullOrWhiteSpace(line))
                   .ToList();

var orderItems = new List<PurchaseOrderItem>();

// 每7行一组循环处理
for (int i = 0; i < lines.Count; i += 7)
{
    var item = new PurchaseOrderItem();
    
    // 提取行号(第1行)
    item.LineNumber = int.Parse(lines[i].Trim());
    
    // 提取数量、零件号(第3行,跳过第2行的EA)
    var partsLine = lines[i+2].Trim().Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
    item.Quantity = decimal.Parse(partsLine[0]);
    item.PartNumber = partsLine[1];
    
    // 提取描述(第4行)
    item.Description = lines[i+3].Trim();
    
    // 提取绘图来源(第5行,冒号后内容)
    item.DrawingSource = lines[i+4].Split(':')[1].Trim();
    
    // 提取到期日(第6行,冒号后、Requester前的内容)
    var dueLine = lines[i+5].Split(new[] { "Requester:" }, StringSplitOptions.None);
    var dueDateStr = dueLine[0].Split(':')[1].Trim();
    item.DueDate = DateTime.Parse(dueDateStr);
    
    orderItems.Add(item);
}

这种方法逻辑清晰,易维护,适合格式完全固定的场景。

方法2:正则表达式匹配(适配小变动)

如果行结构偶尔有微小变动(比如随机空行),可以用正则匹配完整条目:

// 正则匹配每个完整条目,可根据实际格式调整
string pattern = @"(?<LineNumber>\d+)\s+EA\s+(?<Quantity>\d+\.\d+)\s+(?<PartNumber>\w+-\w+-\w+)\s+\d+\.\d+\s+\d+\.\d+\s+(?<Description>.+?)\s+Drawing:\s+(?<DrawingSource>.+?)\s+Due:\s+(?<DueDate>\d{2}/\d{2}/\d{4})";

var regex = new Regex(pattern, RegexOptions.Singleline);
var matches = regex.Matches(rawText);

var orderItems = new List<PurchaseOrderItem>();
foreach (Match match in matches)
{
    var item = new PurchaseOrderItem
    {
        LineNumber = int.Parse(match.Groups["LineNumber"].Value),
        Quantity = decimal.Parse(match.Groups["Quantity"].Value),
        PartNumber = match.Groups["PartNumber"].Value,
        Description = match.Groups["Description"].Value.Trim(),
        DrawingSource = match.Groups["DrawingSource"].Value.Trim(),
        DueDate = DateTime.Parse(match.Groups["DueDate"].Value)
    };
    orderItems.Add(item);
}

正则的优点是兼容小格式变动,缺点是编写和调试稍复杂。

方案对比

  • 按行分组:代码直观,易调试,适合格式稳定的场景。
  • 正则表达式:灵活性强,能适配格式小变化,适合复杂格式场景。

内容的提问来源于stack exchange,提问作者Jfisher387

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 18:45:35