Match maker
Given a CSS query, output the unindented html needed that will produce a match.
For example, a.foo>b#bar
should produce <a class=‘foo’><b id=‘bar’></b></a>
The html should have full tags, not self closing ones. The query follows the following grammar:
query ::= element (">" element)* element ::= name [id] class* id ::= "#" name class ::= "." name name ::= [a-z0-9]+
However for the test cases you should expect at most 9 levels of nesting elements.
Judge
(async function* (context: Context): Challenge { // Single Test const testcases: [string, string][] = [ ["h3#title3.class3", "<h3 id='title3' class='class3'></h3>"], ["figure>figcaption", "<figure><figcaption></figcaption></figure>"], ["span.flair", "<span class='flair'></span>"], ["a.b.c.d", "<a class='b c d'></a>"], ["main>audio.rickroll", "<main><audio class='rickroll'></audio></main>"], [ "table#scores>tbody.bytes>tr.me", "<table id='scores'><tbody class='bytes'><tr class='me'></tr></tbody></table>", ], ["div>div>div", "<div><div><div></div></div></div>"], [ "html>body>main>div.warning", "<html><body><main><div class='warning'></div></main></body></html>", ], [ "html#html>html.html", "<html id='html'><html class='html'></html></html>", ], [ "nav#menu>ul.navlist>li.navitem", "<nav id='menu'><ul class='navlist'><li class='navitem'></li></ul></nav>", ], [ "form#login>input#user.username", "<form id='login'><input id='user' class='username'></input></form>", ], [ "article.blogpost>h1.title", "<article class='blogpost'><h1 class='title'></h1></article>", ], [ "section#about>div.container>p.text", "<section id='about'><div class='container'><p class='text'></p></div></section>", ], [ "div#wrapper>header.main>h2#subtitle", "<div id='wrapper'><header class='main'><h2 id='subtitle'></h2></header></div>", ], [ "footer>div.footercontent>p>a#discord", "<footer><div class='footercontent'><p><a id='discord'></a></p></div></footer>", ], [ "aside#sidebar>div.widget>ul.links", "<aside id='sidebar'><div class='widget'><ul class='links'></ul></div></aside>", ], [ "main#content>section.hero>img.banner", "<main id='content'><section class='hero'><img class='banner'></img></section></main>", ], [ "div.grid>div.cell>span.value", "<div class='grid'><div class='cell'><span class='value'></span></div></div>", ], [ "header#siteheader.siteheader>nav#mainnav>ul.menu>li.item", "<header id='siteheader' class='siteheader'><nav id='mainnav'><ul class='menu'><li class='item'></li></ul></nav></header>", ], [ "alphabet.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z", "<alphabet class='a b c d e f g h i j k l m n o p q r s t u v w x y z'></alphabet>", ], ]; const randomName = () => { const alphabet = "abcdefghijklmnopqrstuvwxyz0123456789"; const length = rand(5) + 5; return Array(length) .fill() .map(() => alphabet[rand(alphabet.length)]) .join(""); }; const populateCase = (k: string, v: string): [string, string] => { const names = range(10).map(() => randomName()); for (let i = 0; i < 10; i++) { k = k.replaceAll("$" + i.toString(), names[i]); v = v.replaceAll("$" + i.toString(), names[i]); } return [k, v]; }; const randCases = [ ["$1>$2", "<$1><$2></$2></$1>"], ["$1#$2.$3>$4", "<$1 id='$2' class='$3'><$4></$4></$1>"], ]; for (const randomCase of randCases) { testcases.push(populateCase(randomCase[0], randomCase[1])); } const hands = context.runTestCases(testcases); for await (const hand of hands) { yield context.registerTestCase(hand); } // Finally, the challenge is passed if no test cases failed return context.noFailures(); });
Example Code
const testcases = require('fs').readFileSync(0).toString().split('\n'); for (const testcase of testcases) { const parts = testcase.split('>'); const tagStack = []; let result = ''; for (const part of parts) { const [tag, ...attributes] = part.split(/(?=[.#])/); tagStack.push(tag); const id = attributes.find(attr => attr.startsWith('#'))?.slice(1); const classList = attributes.filter(attr => attr.startsWith('.')).map(attr => attr.slice(1)).join(' '); const html = `<${tag}${id ? ` id='${id}'` : ''}${classList ? ` class='${classList}'` : ''}>`; result += html; } result += tagStack.reverse().map(tag => `</${tag}>`).join(''); console.log(result); }