Convert a HTML page into a mountain

21

4

Task: convert a HTML page into a mountain!

When HTML pages are indented, they can look like:

<div>
    <div>
        <div>
        </div>
        <div>
            <div>
            </div>
        </div>
    </div>
</div>

But to be honest, a mountain is more representative of this structure.

So we can rewrite it as:

     /\
  /\/  \
 /      \
/        \

The outermost slashes on the left and right correspond to the outer div - each pair of HTML tags should be represented as / for the starting tag and \ for the ending tag - inside all tags are "higher", with the same structure.

Input:

  • There will be no <!DOCTYPE>
  • There will be no self-closing tags e.g. <img /> or <br />
  • There may be attributes or content inside the tags
  • There may be spaces or tabs - your program should ignore these
  • There will be no spaces between < or </ and the tag name
  • All input will be valid HTML

Output - a mountain representing the tags as above.

More testcases:

Input:

<div id="123"> HI </div><a><span></span></a>

Output:

   /\
/\/  \

Input:

<body id="<"></body>

Output:

/\

Solver

Posted 2018-01-08T23:57:37.043

Reputation: 321

18

A word of caution for golfers...

– Luis Mendo – 2018-01-09T00:07:39.360

Will there ever be </ div>? or can we assume the slash is always adjacent to the div – Rɪᴋᴇʀ – 2018-01-09T00:16:28.963

hmmm, I'll be nice - you can assume no spaces after < or </ (until the tag name) - however there may still be spaces for attributes e.g. <div id="aDiv"> – Solver – 2018-01-09T00:18:03.347

5Perhaps this could use a few more test cases? – Birjolaxew – 2018-01-09T18:05:51.013

Can we assume the document would be valid? (i.e. every starting tag has a valid ending one, and the order of the tags is nested properly) – Uriel – 2018-01-10T21:41:10.700

@Uriel yes, of course. – Solver – 2018-01-10T21:41:49.507

Can to-be-ignored text appear before and after the first tag in the document? – Uriel – 2018-01-10T21:43:21.960

No, this will not appear. – Solver – 2018-01-10T21:44:12.410

OK, thanks for the clarifications – Uriel – 2018-01-10T21:50:39.047

Will there ever be any case where there is a poorly written page with incomplete tags such as <div? – juniorRubyist – 2018-01-11T07:54:04.907

1This really needs more test cases, and an exact description (in BNF, say) of what the input will look like. I don’t know what "Valid HTML" means exactly, and how many edge cases I should support. (First one that comes to mind: space between the tag name and > such as <a >b</a >.) – Lynn – 2018-01-13T17:13:23.323

For what it’s worth I think the challenge is interesting enough focusing only on strings like <body><a>xxx</a>yyy<section><div>zzz</div></section></body>. No attributes, only simple matched tags and lowercase letters as text content. HTML is very complex. – Lynn – 2018-01-13T17:17:43.910

I feel like this challenge has turned into an excuse to get people to use JavaScript for golfing. :) though if everyone thinks this is too restrictive, I'll change the question. – Solver – 2018-01-13T17:33:07.107

I call dibs on GNU sed. – SIGSTACKFAULT – 2018-01-14T16:46:42.470

Answers

13

HTML + CSS + JavaScript, 39 + 141 + 20 = 200 bytes

Outputs visually to the webpage. To allow this to work with special elements like <body>, all letters in the input are replaced.

p.innerHTML=prompt().replace(/\w/g,'a')
#p,#p *{display:flex;padding:0 0 1rem;align-items:flex-end;font-size:0}#p :before,#p :after{content:'/';font-size:1rem}#p :after{content:'\\'
<pre id=p>


HTML + CSS + JavaScript, 10 + 103 + 20 = 133 bytes

Solution that works if there is no content within tags.

p.innerHTML=prompt()
#p,#p *{display:flex;padding:0 0 1em;align-items:flex-end}#p :before{content:'/'}#p :after{content:'\\'
<pre id=p>

darrylyeo

Posted 2018-01-08T23:57:37.043

Reputation: 6 214

2This is really clever! – Rick Hitchcock – 2018-01-09T23:00:04.827

1I've never seen golfed CSS before :) – Solver – 2018-01-11T08:03:17.207

This fails both of the test cases. – Giuseppe – 2018-01-12T14:12:32.317

@Giuseppe I think you may be able to fix it with display = none on all elements and using an iframe instead of a <pre> – Solver – 2018-01-12T18:11:51.940

@Giuseppe Fixed. – darrylyeo – 2018-01-13T16:35:37.050

6

Javascript + JQuery, 275 246 bytes

Saved 29 bytes thanks to Rick Hitchcock

j=(a,b,c,i)=>{s=(c=' '.repeat(b))+'/\n';for(i=0;V=a.children[i];i++){s=s+j(V,b+1)}return s+c+'\\\n';};f=s=>{s=j($(s)[0],0).split`
`;w=Math.max.apply(0,s.map(a=>a.length));o='';for(i=w-1;i>=0;i--){for(c=0;C=s[c];c++){o+=C[i]||' '}o+='\n'}alert(o)}

A pretty Naïve solution to the problem. Parses the HTML with JQuery's $(string), then recursively builds a sideways mountain with the format:

/
 /
  children...
 \
\

Then rotates the resulting string counterclockwise, and alerts the result.

    j=(a,b,c,i)=>{s=(c=' '.repeat(b))+'/\n';for(i=0;V=a.children[i];i++){s=s+j(V,b+1)}return s+c+'\\\n';};f=s=>{s=j($(s)[0],0).split`
`;w=Math.max.apply(0,s.map(a=>a.length));o='';for(i=w-1;i>=0;i--){for(c=0;C=s[c];c++){o+=C[i]||' '}o+='\n'}return o}

update=_=>outp.textContent=f(inp.value)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea id=inp oninput=update()></textarea>
<pre id=outp></pre>

ATaco

Posted 2018-01-08T23:57:37.043

Reputation: 7 898

Are you sure it's naïve and not naïve? (I can stop this joke if you want) – Esolanging Fruit – 2018-01-09T02:32:51.070

269 bytes by changing to: j=(a,b,c,i)=>{s=(c=' '.repeat(b))+'/\n';for(i ... – Rick Hitchcock – 2018-01-09T20:41:33.420

Change to for(c=0;c<s.length;c++) to for(c=0;s[c];c++) – Rick Hitchcock – 2018-01-09T20:47:00.337

Similarly, change for(i=0;i<a.children.length;i++) to for(i=0;a.children[i];i++) – Rick Hitchcock – 2018-01-09T20:50:42.253

3

HTML + JavaScript (ES6), 8 + 192 = 200 bytes

JS

s=>[...(E.innerHTML=s,y=0,o=[],m=n=>1+[...n.children].map(m).join``+0)(E.firstChild)].map((c,x,a)=>{(o[y+=+c]||(o[y]=[...a].fill` `))[x]=`\\/`[c],y+=~-c})&&o.reverse().map(l=>l.join``).join`
`

HTML

<a id=E>

f=

s=>[...(E.innerHTML=s,y=0,o=[],m=n=>1+[...n.children].map(m).join``+0)(E.firstChild)].map((c,x,a)=>{(o[y+=+c]||(o[y]=[...a].fill` `))[x]=`\\/`[c],y+=~-c})&&o.reverse().map(l=>l.join``).join`
`

console.log(f(`<div>
    <div>
        <div>
        </div>
        <div>
        </div>
        <div>
            <div>
            </div>
        </div>
    </div>
</div>`))
<a id=E>

Less golfed

s=>{
    E.innerHTML=s,
    y=0,
    o=[],
    m=n=>1+[...n.children].map(m).join``+0,
    [...m(E.firstChild)].map((c,x,a)=>{
        y+=+c
        if(!o[y]) o[y]=[...a].fill` `
        o[y][x]=`\\/`[c]
        y+=~-c
    })
    return o.reverse().map(l=>l.join``).join`\n`
}

darrylyeo

Posted 2018-01-08T23:57:37.043

Reputation: 6 214

Shouldn't the byte count include the id=E HTML element since you are relying on it for the code to work? – Birjolaxew – 2018-01-10T01:55:56.023

@Birjolaxew Whoops! I missed that somehow. – darrylyeo – 2018-01-10T03:51:11.583

1HTML has built-in HTML parser... creative solution. – user202729 – 2018-01-10T13:19:34.433

1

05AB1E, 38 26 23 bytes

¶¡εDð¢4÷s'/å_„\/sèú}ζR»

Try it online!


I am still golfing this. It assumes that in HTML you will always use 4 spaces for indentation, and does not work on "non-pretty" HTML. Not sure how to handle the "content" part, if this is invalid please edit the question to show an example with a node that has content.

Magic Octopus Urn

Posted 2018-01-08T23:57:37.043

Reputation: 19 422

0

Charcoal, 28 bytes

≔¹ηF⮌θ«≡ι"≦¬η<Fη¿⁼ζ/←¶\↙/≔ιζ

Try it online! Link is to verbose version of code. Explanation:

≔¹η

The h variable is used to keep track of whether we are inside quotes.

F⮌θ«

Loop over the string in reverse order.

≡ι

Switch on the currenc character.

"≦¬η

If it's a " then toggle the quote flag.

<Fη

If it's a < and we're not inside quotes, then...

¿⁼ζ/

If the next character (previous in the loop because we're looping in reverse) is a /, then...

←¶\

Move up and draw a \ leftwards, else...

↙/

Draw a / and move down and left.

≔ιζ

Remember the character for the next loop iteration.

Neil

Posted 2018-01-08T23:57:37.043

Reputation: 95 035