xyc
9 天以前 3b68e9e811b9edc5a7abf7c53be37d6274f51d7d
docs/Ͷ×Ê/¹¤¾ß/ÊÐÖÝÔ±¨½âÎö.py
@@ -76,21 +76,14 @@
    return str(v)
def pick_columns(cell, nrows, ncols):
    """按表头关键字定位列;同一字段命中多次时,取“行号最小、其次是命中词最短”的那个。"""
    hits = F.scan_fields(cell, nrows, ncols)
    cols = {}
    for f in FIELDS:
        if f not in hits:
            continue
        best = sorted(hits[f], key=lambda h: (h[0], len(h[2])))[0]
        cols[f] = F.colindex(best[1])
    return cols, hits
def pick_columns(cell, nrows, ncols, merges=None):
    """按表头定位列(含两级表头消歧)——实现见 æ ¼å¼æŽ¢æµ‹.py çš„ pick_columns,保证两处口径一致。"""
    return F.pick_columns(cell, nrows, ncols, merges, fields=FIELDS)
def parse_sheet(cell, nrows, ncols, city=None):
def parse_sheet(cell, nrows, ncols, city=None, merges=None):
    """解析一张工作表 â†’ (项目行列表, æ®µä¿¡æ¯, æ ¡éªŒä¿¡æ¯)"""
    cols, hits = pick_columns(cell, nrows, ncols)
    cols, hits = pick_columns(cell, nrows, ncols, merges)
    namec = cols.get('项目名称')
    if namec is None:
        return [], {}, {}
@@ -181,7 +174,7 @@
    bodies = [a.body] if a.body else ['客运(客运站)', '物流(物流园区)']
    md = '%d月' % int(a.month.split('-')[1])
    records, report = [], []
    records, report, checks = [], [], []
    report.append('# å¸‚州月报解析报告(%s)' % a.month)
    report.append('')
    report.append('(只读解析;一行一个项目行,明细见同名 `.tsv`)')
@@ -207,23 +200,38 @@
                sel = F.pick_sheet(sheets, ym=ym)
                if not sel:
                    report.append('| %s | ï¼ˆæœªé€‰ä¸­å·¥ä½œè¡¨ï¼‰ | | | | | |' % f[:44])
                    checks.append({'品类': body_key, '市州': city_file or '', '文件': f, '工作表': '',
                                   '状态': '未选中工作表', '项目行数': 0, '一致性': '—'})
                    continue
                nm, nr, nc, cell, _hits = sel
                rows, seg, extra = parse_sheet(cell, nr, nc, city=city_file)
                merges = F.sheet_merges(path).get(nm, [])
                rows, seg, extra = parse_sheet(cell, nr, nc, city=city_file, merges=merges)
                city = seg.get('市州') or city_file or city_by_override(f) or ''
                sums = {k: sum(num(r.get(k)) or 0 for r in rows) for k in NUM_FIELDS}
                sub = extra.get('小计合计行') or {}
                sub_txt, ok = [], '—'
                if not sub and extra.get('市州行值'):
                    sub = {'R%s(市州行)' % (seg.get('市州行') or '?'): extra['市州行值']}
                tok = tval = None
                if sub:
                    key, val = pick_total(sub)
                    tok, tval = key, val
                    sub_txt.append('%s=%s' % (key, '/'.join(pretty(val.get(k)) for k in ('自开始建设累计', '自年初累计', '本月完成'))))
                    if len(sub) > 1:
                        sub_txt.append('(另有 %d è¡Œå°è®¡/合计)' % (len(sub) - 1))
                    same = all(abs((val.get(k) or 0) - sums[k]) < 0.05
                               for k in ('自开始建设累计', '自年初累计', '本月完成'))
                    ok = '✅ ä¸€è‡´' if same else '⚠️ ä¸ä¸€è‡´'
                ck = {'品类': body_key, '市州': city, '文件': f, '工作表': nm, '状态': 'OK',
                      '项目行数': len(rows), '合计行': '', '一致性': ok,
                      '列位': ','.join('%s=%s' % (k, v) for k, v in (extra.get('列位') or {}).items())}
                for k in ('自开始建设累计', '自年初累计', '本月完成'):
                    ck['求和_' + k] = sums[k]
                if sub:
                    ck['合计行'] = tok
                    for k in ('自开始建设累计', '自年初累计', '本月完成'):
                        ck['合计_' + k] = tval.get(k)
                checks.append(ck)
                report.append('| %s | %s | %s | %d | %s | %s | %s |' % (
                    f[:44], nm[:14], city, len(rows),
                    '/'.join(pretty(sums[k]) for k in ('自开始建设累计', '自年初累计', '本月完成')),
@@ -234,6 +242,9 @@
                    records.append(rec)
            except Exception as e:
                report.append('| %s | ï¼ˆè§£æžå¤±è´¥ï¼š%s: %s) | | | | | |' % (f[:44], type(e).__name__, str(e)[:60]))
                checks.append({'品类': body_key, '市州': city_file or '', '文件': f, '工作表': '',
                               '状态': '解析失败:%s: %s' % (type(e).__name__, str(e)[:80]),
                               '项目行数': 0, '一致性': '—'})
        report.append('')
    # å¸‚州汇总(跨文件合并同市州)
@@ -254,6 +265,28 @@
            *(pretty(s[f]) for f in ('总投资', '自开始建设累计', '本年计划投资', '自年初累计', '本月完成'))))
    report.append('')
    report.append('## å„源文件识别到的列位(**按表头关键字定位,不是固定列号**)')
    report.append('')
    report.append('| å“ç±» | æ–‡ä»¶ | å·¥ä½œè¡¨ | é¡¹ç›®åç§° | æ€»æŠ•资 | è‡ªå¼€å§‹å»ºè®¾ç´¯è®¡ | æœ¬å¹´è®¡åˆ’投资 | è‡ªå¹´åˆç´¯è®¡ | æœ¬æœˆå®Œæˆ |')
    report.append('| --- | --- | --- | --- | --- | --- | --- | --- | --- |')
    _key5 = ('项目名称', '总投资', '自开始建设累计', '本年计划投资', '自年初累计', '本月完成')
    for ck in checks:
        _cm = dict(kv.split('=', 1) for kv in (ck.get('列位') or '').split(',') if '=' in kv)
        report.append('| %s | %s | %s | %s |' % (ck.get('品类', ''), ck.get('文件', '')[:34], ck.get('工作表', '')[:12],
                                                 ' | '.join(_cm.get(k, '—') for k in _key5)))
    report.append('')
    ck_cols = ['品类', '市州', '文件', '工作表', '状态', '项目行数', '一致性', '合计行', '列位',
               '求和_自开始建设累计', '求和_自年初累计', '求和_本月完成',
               '合计_自开始建设累计', '合计_自年初累计', '合计_本月完成']
    p_ck = os.path.join(out, '解析校验_%s.tsv' % a.month)
    with io.open(p_ck, 'w', encoding='utf-8-sig') as fh:
        fh.write('\t'.join(ck_cols) + '\n')
        for c in checks:
            fh.write('\t'.join(pretty(c.get(k, '')) if isinstance(c.get(k), float) else str(c.get(k, ''))
                                for k in ck_cols) + '\n')
    print('校验记录数 = %d' % len(checks))
    cols = ['品类', '市州', '文件', '工作表', '行号', '序号', '分类'] + FIELDS
    tsv = os.path.join(out, '解析结果_%s.tsv' % a.month)
    with io.open(tsv, 'w', encoding='utf-8-sig') as fh:
@@ -265,6 +298,7 @@
    print('项目行合计 = %d' % len(records))
    print('wrote', p_md)
    print('wrote', tsv)
    print('wrote', p_ck)
if __name__ == '__main__':