跳至內容
Astera Technology

按指定問題分隔符把批次答案配回原題

解析自訂原始答案標記及轉義,保留錯邊界與未配對文字。

下載完整個案資料及參考答案 ↓

訂明本例驗收任務

假設原始答案流用整行 @@Q:ID@@ 開答案,@@END@@ 關答案;編號只用英文字母、數字及連字號。行首反斜線會去掉首字,餘下原樣當內容,即使像標記也一樣。框外非空字留作未配對。嵌套開框、重複已完成編號、無開框的結束、錯標記或未閉框都停解析,保留已完成及未閉內容;不按輸出次序配題。

  1. 解析整行開閉標記
  2. 轉義行原樣留作內容
  3. 保留錯格式及未配對內容

解析錯誤保留已完成答案及現未閉框,須修原始答案流。

使用已填個案

原創假設輸入及確切答案鍵
個案已提供輸入預期結構化結果判斷及原因
Q2 答案先於 Q1{"raw":"@@Q:Q2@@\nsecond\n@@END@@\n@@Q:Q1@@\nfirst\n@@END@@"}{"answers":[{"id":"Q2","text":"second"},{"id":"Q1","text":"first"}],"unassigned":[],"open":null,"error":null,"ready":true}按整行標記配答案編號,不按先後位置。
轉義標記仍是內容{"raw":"@@Q:Q1@@\n\\@@Q:FAKE@@\n@@END@@"}{"answers":[{"id":"Q1","text":"@@Q:FAKE@@"}],"unassigned":[],"open":null,"error":null,"ready":true}行首轉義令看似 FAKE 開框留作答案原文。
未閉答案內又開框{"raw":"@@Q:Q1@@\n@@Q:Q2@@"}{"answers":[],"unassigned":[],"open":{"id":"Q1","lines":[]},"error":{"code":"nested-start","line":2},"ready":false}第二個開框不能默默丟掉 Q1,保留未閉狀態及錯行。
答案框外文字{"raw":"Intro\n@@Q:Q1@@\nanswer\n@@END@@"}{"answers":[{"id":"Q1","text":"answer"}],"unassigned":["Intro"],"open":null,"error":null,"ready":false}Q1 框有效並保留,Intro 未配對,不能列全部已備好。
答案欠結束標記{"raw":"@@Q:Q1@@\nanswer"}{"answers":[],"unassigned":[],"open":{"id":"Q1","lines":["answer"]},"error":{"code":"unclosed-block","line":2},"ready":false}按已訂原始格式,這段答案尚未完整。
編號內有空格{"raw":"@@Q:Q 1@@"}{"answers":[],"unassigned":[],"open":null,"error":{"code":"malformed-marker","line":1},"ready":false}像標記但編號無效的行,不當普通資料文字。
下載可編輯 CSV ↓

逐步處理 malformed-id-marker 個案,須得到甚麼結果?原因是甚麼?

查看參考答案

{"answers":[],"unassigned":[],"open":null,"error":{"code":"malformed-marker","line":1},"ready":false}。像標記但編號無效的行,不當普通資料文字。

執行完整本機驗算

另存為 .mjs,以 Node.js 執行;只驗提供的個案
import assert from 'node:assert/strict';

function evaluate(x){
 const lines=x.raw.split('\n'),answers=[],unassigned=[];let open=null;
 const fail=(code,line)=>({answers,unassigned,open,error:{code,line},ready:false});
 const literal=text=>{if(open)open.lines.push(text);else if(text!=='')unassigned.push(text);};
 for(let i=0;i<lines.length;i++){const line=lines[i];if(line.charCodeAt(0)===92){literal(line.slice(1));continue;}
 const m=/^@@Q:([A-Za-z0-9-]+)@@$/.exec(line);if(m){if(open)return fail('nested-start',i+1);if(answers.some(a=>a.id===m[1]))return fail('duplicate-id',i+1);open={id:m[1],lines:[]};}
 else if(line==='@@END@@'){if(!open)return fail('unmatched-end',i+1);answers.push({id:open.id,text:open.lines.join('\n')});open=null;}
 else if(line.startsWith('@@'))return fail('malformed-marker',i+1);else literal(line);
 }
 if(open)return fail('unclosed-block',lines.length);return {answers,unassigned,open:null,error:null,ready:unassigned.length===0};
}

const cases = [
  {
    "id": "reverse-answer-order",
    "input": {
      "raw": "@@Q:Q2@@\nsecond\n@@END@@\n@@Q:Q1@@\nfirst\n@@END@@"
    },
    "expected": {
      "answers": [
        {
          "id": "Q2",
          "text": "second"
        },
        {
          "id": "Q1",
          "text": "first"
        }
      ],
      "unassigned": [],
      "open": null,
      "error": null,
      "ready": true
    }
  },
  {
    "id": "escaped-literal-marker",
    "input": {
      "raw": "@@Q:Q1@@\n\\@@Q:FAKE@@\n@@END@@"
    },
    "expected": {
      "answers": [
        {
          "id": "Q1",
          "text": "@@Q:FAKE@@"
        }
      ],
      "unassigned": [],
      "open": null,
      "error": null,
      "ready": true
    }
  },
  {
    "id": "nested-start",
    "input": {
      "raw": "@@Q:Q1@@\n@@Q:Q2@@"
    },
    "expected": {
      "answers": [],
      "unassigned": [],
      "open": {
        "id": "Q1",
        "lines": []
      },
      "error": {
        "code": "nested-start",
        "line": 2
      },
      "ready": false
    }
  },
  {
    "id": "unassigned-preamble",
    "input": {
      "raw": "Intro\n@@Q:Q1@@\nanswer\n@@END@@"
    },
    "expected": {
      "answers": [
        {
          "id": "Q1",
          "text": "answer"
        }
      ],
      "unassigned": [
        "Intro"
      ],
      "open": null,
      "error": null,
      "ready": false
    }
  },
  {
    "id": "unclosed-answer",
    "input": {
      "raw": "@@Q:Q1@@\nanswer"
    },
    "expected": {
      "answers": [],
      "unassigned": [],
      "open": {
        "id": "Q1",
        "lines": [
          "answer"
        ]
      },
      "error": {
        "code": "unclosed-block",
        "line": 2
      },
      "ready": false
    }
  },
  {
    "id": "malformed-id-marker",
    "input": {
      "raw": "@@Q:Q 1@@"
    },
    "expected": {
      "answers": [],
      "unassigned": [],
      "open": null,
      "error": {
        "code": "malformed-marker",
        "line": 1
      },
      "ready": false
    }
  }
];
for (const c of cases) assert.deepEqual(evaluate(c.input), c.expected, c.id);
console.log(JSON.stringify({checked:cases.length,caseIds:cases.map(c=>c.id)}));
下載可執行例子 ↓

把此格式連批次驗收表保存。這是自訂本機分隔規則,不是供應商格式;明訂 LF 換行,換行或轉義規則改動須另加個案。

相關資源