| |
| |
| """ |
| Step5 解析器(稳健版) |
| - 兼容中文全角/半角、圆括号/方括号、中文/英文逗号 |
| - 抽取:增强后的指令 + 逐帧 bbox(与采样 t 序列对齐) |
| - 校验:0<=x1<x2<=1, 0<=y1<y2<=1;不合法则记为 None |
| """ |
|
|
| import re |
| from typing import Dict, List, Tuple |
|
|
| CN2NUM = { |
| "一": 1, "二": 2, "三": 3, "四": 4, "五": 5, |
| "六": 6, "七": 7, "八": 8, "九": 9, "十": 10 |
| } |
|
|
| |
| FULL2HALF_MAP = str.maketrans({ |
| "(": "(", ")": ")", "【": "[", "】": "]", "[": "[", "]": "]", |
| ",": ",", ":": ":", ";": ";", "。": ".", "、": ",", "|": "|", |
| }) |
|
|
| def _normalize_text(s: str) -> str: |
| s = (s or "").strip().replace("\u00A0", " ").replace("\t", " ") |
| |
| s = re.sub(r"[ ]{2,}", " ", s) |
| return s.translate(FULL2HALF_MAP) |
|
|
| def _extract_enhanced_instruction(step5_line: str) -> str: |
| """ |
| 支持两种写法: |
| 1) 修改后的编辑指令:{ ... },任务一boxing序列: |
| 2) 修改后的编辑指令:...,任务一boxing序列: |
| 同时兼容中文/英文逗号,冒号,花括号可选 |
| """ |
| |
| m = re.search(r"修改后的编辑指令[::]\s*\{(?P<inst>.+?)\}\s*[,,]", step5_line) |
| if m: |
| return m.group("inst").strip() |
| |
| m = re.search( |
| r"修改后的编辑指令[::]\s*(?P<inst>.+?)\s*[,,]\s*任务\s*[一二三四五六七八九十\d]+\s*boxing序列[::]", |
| step5_line |
| ) |
| return m.group("inst").strip() if m else "" |
|
|
| def _task_key_to_idx(tok: str) -> int: |
| |
| m = re.search(r"任务\s*([一二三四五六七八九十\d]+)", tok) |
| if not m: |
| return 1 |
| key = m.group(1) |
| return CN2NUM.get(key, int(key) if key.isdigit() else 1) |
|
|
| def parse_step5(step5_line: str, t_list: List[int]) -> Tuple[str, Dict[str, List[Dict]]]: |
| """ |
| 返回 (enhanced_instruction, tasks_json) |
| tasks_json 结构: |
| { |
| "任务一": [{"t": t0, "bbox":[x1,y1,x2,y2] or None}, ...], |
| ... |
| } |
| """ |
| s = _normalize_text(step5_line) |
|
|
| enhanced = _extract_enhanced_instruction(s) |
|
|
| |
| |
| parts = re.split(r"(任务[一二三四五六七八九十\d]+\s*boxing序列[::])", s) |
| tasks_json: Dict[str, List[Dict]] = {} |
|
|
| def parse_seq(seq_txt: str) -> List[Dict]: |
| """ |
| 解析形如: |
| [(t=0,[(0.64,0.68,0.71,0.78)]);(t=1,[(0.64,0.68,0.71,0.78)])] |
| 允许 () 或 [] 包围 bbox,允许中文逗号/空格。 |
| """ |
| seq_txt = (seq_txt or "").strip() |
| |
| items = re.split(r"[;;]+", seq_txt.strip("[] ")) |
| out = [] |
| for it in items: |
| it = it.strip() |
| if not it: |
| continue |
| |
| mt = re.search(r"t\s*=\s*(\d+)", it) |
| if not mt: |
| continue |
| t = int(mt.group(1)) |
|
|
| |
| mb = re.search(r"\[\s*([\d\.\s,,]+)\s*\]|\(\s*([\d\.\s,,]+)\s*\)", it) |
| if not mb: |
| out.append({"t": t, "bbox": None}) |
| continue |
|
|
| nums_str = (mb.group(1) or mb.group(2) or "").replace(",", ",") |
| nums = [x for x in re.split(r"\s*,\s*", nums_str) if x] |
| if len(nums) != 4: |
| out.append({"t": t, "bbox": None}) |
| continue |
|
|
| try: |
| x1, y1, x2, y2 = map(float, nums) |
| except Exception: |
| out.append({"t": t, "bbox": None}) |
| continue |
|
|
| ok = (0.0 <= x1 < x2 <= 1.0) and (0.0 <= y1 < y2 <= 1.0) |
| out.append({"t": t, "bbox": [x1, y1, x2, y2]} if ok else {"t": t, "bbox": None}) |
| return out |
|
|
| |
| for i in range(1, len(parts), 2): |
| head = parts[i] |
| body = parts[i + 1] if i + 1 < len(parts) else "" |
| idx = _task_key_to_idx(head) |
| key = f"任务{idx}" |
| tasks_json[key] = parse_seq(body) |
|
|
| |
| def align(seq: List[Dict]) -> List[Dict]: |
| by_t = {e["t"]: e for e in seq} |
| aligned = [] |
| for t in t_list: |
| e = by_t.get(t) |
| aligned.append(e if e else {"t": t, "bbox": None}) |
| return aligned |
|
|
| tasks_json = {k: align(v) for k, v in tasks_json.items()} |
| return enhanced, tasks_json |
|
|