Skip to content
Astera Technology

Associate batched answers using supplied question delimiters

Parse a local escaped delimiter grammar with malformed boundaries and unassigned output retained.

Download complete case notes and answer keys ↓

Define the local evaluation task

A synthetic raw answer stream uses whole-line @@Q:ID@@ to open one answer and @@END@@ to close it. IDs contain ASCII letters, digits or hyphens. A line starting with a backslash loses that first character and is literal content, even if it resembles a marker. Nonempty text outside a block is retained as unassigned. Nested starts, repeated completed IDs, unmatched ends, malformed marker lines and unclosed blocks stop parsing with retained prior answers and open content. Nothing is mapped by output position.

  1. Parse whole-line start/end markers
  2. Preserve escaped lines as literal content
  3. Retain malformed and unassigned material

Parsing errors retain prior completed answers and the current open block; staff must repair the raw stream.

Use the filled cases

Original synthetic input and literal answer key
CaseSupplied inputExpected structured outputDecision and reason
Q2 arrives before 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}Whole-line markers bind each answer ID regardless of arrival order.
Escaped marker remains content{"raw":"@@Q:Q1@@\n\\@@Q:FAKE@@\n@@END@@"}{"answers":[{"id":"Q1","text":"@@Q:FAKE@@"}],"unassigned":[],"open":null,"error":null,"ready":true}The leading escape makes the apparent FAKE start literal answer text.
Start inside an open answer{"raw":"@@Q:Q1@@\n@@Q:Q2@@"}{"answers":[],"unassigned":[],"open":{"id":"Q1","lines":[]},"error":{"code":"nested-start","line":2},"ready":false}The second opener cannot silently abandon Q1; retain the open state and error line.
Text outside an answer{"raw":"Intro\n@@Q:Q1@@\nanswer\n@@END@@"}{"answers":[{"id":"Q1","text":"answer"}],"unassigned":["Intro"],"open":null,"error":null,"ready":false}The valid Q1 block is retained, but Intro remains unassigned and blocks ready status.
Answer lacks end marker{"raw":"@@Q:Q1@@\nanswer"}{"answers":[],"unassigned":[],"open":{"id":"Q1","lines":["answer"]},"error":{"code":"unclosed-block","line":2},"ready":false}The apparent answer is incomplete under the declared raw grammar.
ID contains forbidden space{"raw":"@@Q:Q 1@@"}{"answers":[],"unassigned":[],"open":null,"error":{"code":"malformed-marker","line":1},"ready":false}A marker-looking line with an invalid ID is not ordinary payload text.
Download editable CSV ↓

Work the malformed-id-marker case. Which output is required, and why?

Show the worked answer

{"answers":[],"unassigned":[],"open":null,"error":{"code":"malformed-marker","line":1},"ready":false} — A marker-looking line with an invalid ID is not ordinary payload text.

Run the self-contained evaluator

Save as .mjs and run with Node.js; supplied fixtures only
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)}));
Download runnable example ↓

Copy this grammar with the batch acceptance sheet. It is an original local delimiter protocol, not a provider output format. Raw LF line endings are explicit; a different newline or escaping rule needs new fixtures.

Related resources