How to extract a pattern into a grid using regex?

I am using quarto to type and typst as output. i define typst-show.typ and typst-template.typ.
Currently my issue is this

## Fill in the blanks (10*2 = 20 Marks)

I have a level 2 heading in my qmd file and a section of typst-template.typ


#show heading.where(level: 2): it => {
  let txt = str(it)

  // Match and capture the text inside parentheses
  let m = regex("\\((.+)\\)").find(txt)

  grid(
    columns: (70%, 30%),
    align(left)[
      // Remove parentheses part from left title
      str.replace(txt, regex("\\s*\\(.+\\)"), "")
    ],
    align(right)[
      // Show only the captured group (without parentheses)
      if m != none { *{m.captures.at(0)}* }
    ]
  )
}

What i want to achieve is this. Any thing inside parenthesis in quarto should be captured and kept inside 2nd column of the grid. i dont want parenthsis in both columns in final output.

What i want is this

Fill in the blanks 10*1 = 10 Marks

Not sure if you have to have 70/30 column width ratio, but here it is:

#import "@preview/t4t:0.4.3": get

#show heading.where(level: 2): it => {
  let text = get.text(it)

  // Match and capture the text inside parentheses
  let pattern = "\\s*\\((.+)\\)"
  let match = text.match(regex(pattern))
  if match == none { return it }

  grid(
    columns: (70%, 30%),
    align: (left, right),
    // Remove parentheses part from left title
    text.replace(regex(pattern), ""),
    // Show only the captured group (without parentheses)
    strong(match.captures.at(0)),
  )
}

== Fill in the blanks (10*2 = 20 Marks)

== Fill in the blanks

image

#import "@preview/t4t:0.4.3": get

#show heading.where(level: 2): it => {
  let text = get.text(it)
  let pattern = "\\s*\\((.+)\\)"
  let match = text.match(regex(pattern))
  if match == none { return it }
  let left = text.replace(regex(pattern), "")
  let right = strong(match.captures.at(0))
  block(left + h(1fr) + right)
}

I wouldn’t put my life on t4t, but I think its get.text has improved with time, and probably is more reliable than it used to.

This worked. But then i ran to some other problem

#show heading.where(level: 2): it => {
  let text = get.text(it)

  // Match and capture the text inside parentheses
  let pattern = "\\s*\\((.+)\\)"
  let match = text.match(regex(pattern))
  if match == none { return it }

  grid(
    columns: (70%, 30%),
    align: (left, right),
    // Rebuild heading so numbering is preserved
    heading(
      level: 2,
      numbering: "I",     // Roman numerals
      supplement: none,   // removes auto numbering prefix duplication
      text.replace(regex(pattern), "")
    ),
    strong(match.captures.at(0)),
  )
}

if i use this and level two headings headings return as NI, NII,NIII etc. How can i fix this?

Calling element constructor inside its show rule leads to infinite recursion. Use Add default typst implementation code where possible · Issue #5095 · typst/typst · GitHub.

1-level heading should exist before 2-level heading.

#import "@preview/t4t:0.4.3": get

#set heading(numbering: "I.I")

#show heading.where(level: 2): it => {
  let text = get.text(it)

  // Match and capture the text inside parentheses
  let pattern = "\\s*\\((.+)\\)"
  let match = text.match(regex(pattern))
  if match == none { return it }

  let SPACING_TO_NUMBERING = 0.3em
  let realized = text.replace(regex(pattern), "")
  let indent = if it.hanging-indent == auto { 0pt } else { it.hanging-indent }

  if it.numbering != none {
    let numbering = counter(heading).display(it.numbering)
    let spacing = h(SPACING_TO_NUMBERING, weak: true)
    if it.hanging-indent == auto {
      indent = measure(numbering).width + SPACING_TO_NUMBERING
    }
    realized = numbering + spacing + realized
  }

  grid(
    columns: (70%, 30%),
    align: (left, right),
    realized,
    strong(match.captures.at(0)),
  )
}

= this
== Text (other text)
== Text (other text)

image

I did not understand.Sorry!

#import "@preview/t4t:0.3.0": get

#let marks(mk, qs) = [
  #mk × #qs = #(mk * qs)
]

#show heading.where(level: 1): it => align(center, it) 
#set par(
  justify: true
)
#set enum(spacing: 1.2em, numbering: "1.")
// #show heading.where(level: 2): set heading(numbering: "1")
#show heading.where(level: 2): it => {
  let text = get.text(it)

  // Match and capture the text inside parentheses
  let pattern = "\\s*\\((.+)\\)"
  let match = text.match(regex(pattern))
  if match == none { return it }

  grid(
    columns: (70%, 30%),
    align: (left, right),
    // Rebuild heading so numbering is preserved
   text.replace(regex(pattern), ""),
    strong(match.captures.at(0)),
  )
}


#let article(
  // The book's title.
  title: "Book title",

  subtitle: "Subtitle",

  // The book's author.
  author: "Author",

  // The book's author.
  roll_number: "default",

  // The paper size to use.
  paper: "a4",

  section_info: (:),

  date: none,
  
  // The book's content.
  body,
) = {
  // Set the document's metadata.
  set document(title: title, author: author)

  // Set the body font.
  //set text(font: "Source Sans Pro")

  // Configure the page properties.
  set page(
    paper: paper,
    margin: (bottom: 1cm, top: 1cm, left: 2.5cm, right: 2.5cm),
  )
  //show heading.where(level: 1): set heading(numbering: "1")
  
  
  page([
#align(center)[#text(size: 16pt)[*KERALA AGRICULTURAL UNIVERSITY*]]
#v(0.2em)
#align(center)[#text(size: 14pt)[College of Cooperation Banking and Management]] 
#v(0.2em)
#align(center)[
*BSc.(Hons) Cooperation and Banking*]

#v(1em)

    #body
  ])
}

I already have a level 1 heading. just that it is not numbered. Since that is the case I want level 2 heading to display numbers like I, II etc. not I.1, I.2 etc. Is it not possible?

#import "@preview/t4t:0.3.0": get

#let marks(mk, qs) = [#mk #sym.times #qs = #(mk * qs)]

#let article(
  // The book's title.
  title: "Book title",
  subtitle: "Subtitle",
  // The book's author.
  author: "Author",
  // The book's author.
  roll_number: "default",
  // The paper size to use.
  paper: "a4",
  section_info: (:),
  date: none,
  // The book's content.
  body,
) = {
  // Set the document's metadata.
  set document(title: title, author: author)

  // Set the body font.
  // set text(font: "Source Sans Pro")

  // Configure the page properties.
  set page(
    paper: paper,
    margin: (bottom: 1cm, top: 1cm, left: 2.5cm, right: 2.5cm),
  )

  set par(justify: true)

  // show heading.where(level: 1): set heading(numbering: "1")
  show heading.where(level: 1): set align(center)
  show heading.where(level: 2): set heading(
    numbering: (a, b) => numbering("I", b),
  )
  show heading.where(level: 2): it => {
    let text = get.text(it)

    // Match and capture the text inside parentheses
    let pattern = "\\s*\\((.+)\\)"
    let match = text.match(regex(pattern))
    if match == none { return it }

    let SPACING_TO_NUMBERING = 0.3em
    let realized = text.replace(regex(pattern), "")

    if it.numbering != none {
      let numbering = counter(heading).display(it.numbering)
      let spacing = h(SPACING_TO_NUMBERING, weak: true)
      realized = numbering + spacing + realized
    }

    grid(
      columns: (70%, 30%),
      align: (left, right),
      // Rebuild heading so numbering is preserved
      realized, strong(match.captures.at(0)),
    )
  }

  align(center, {
    text(16pt)[*KERALA AGRICULTURAL UNIVERSITY*]
    v(0.2em)
    text(14pt)[College of Cooperation Banking and Management]
    v(0.2em)
    [*BSc. (Hons) Cooperation and Banking*]
    v(1em)
  })

  body
}

#show: article

= 1-level
== 2-level
== 2-level (something)

Top-level headings normally have numbering, and lower-level headings do not. To do the other way around, you will have to create a custom numbering function.