7
\$\begingroup\$

Given an inconsistently indented piece of html code your task is to return the same text but correctly indented

  • Indent space = 4
  • Assume input will be non-empty.
  • Input can be taken as string or array/list of lines
  • Opening and closing tags must be on the same line as long as there is not any other tag inside. <td></td>
  • Assume there will be only html tags, no text elements whatsoever
  • All opening tags that aren't self-closing will have closing tags, and will be given in the correct nesting order. Self-closing tags will be closed with />
  • Standard rules apply

Example and test-cases

Input
--------------
<table>
     <tr>
  <td>
</td>
      <td></td></tr></table> 

Output
----------
<table>
    <tr>
        <td></td>
        <td></td>
    </tr>
</table>

Input
------------
<div>
              <ul>
<li></li><li></li></ul>
        <ul>
              <li></li>
<li></li>
</ul><div><table>

<tbody>
  <thead>
 <tr>
        <th></th>
          <th></th>
             </tr>
       </thead>
   <tbody>
<tr>
    <td></td>
    <td></td>
</tr>
<tr>
    <td></td>
    <td></td>
</tr>
</tbody></tbody></table>
       </div>
</div>

Output
--------------------
<div>
    <ul>
        <li></li>
        <li></li>
    </ul>
    <ul>
        <li></li>
        <li></li>
    </ul>
    <div>
        <table>
            <tbody>
                <thead>
                    <tr>
                        <th></th>
                        <th></th>
                    </tr>
                </thead>
                <tbody>
                    <tr>
                        <td></td>
                        <td></td>
                    </tr>
                    <tr>
                        <td></td>
                        <td></td>
                    </tr>
                </tbody>
            </tbody>
        </table>
    </div>
</div>

Input
--------------
<div><img src=""/><p></p><input/><input/></div>

Output
-------------
<div>
    <img src=""/>
    <p></p>
    <input/>
    <input/>
</div>
\$\endgroup\$
18
  • 2
    \$\begingroup\$ Do we need to support single-label tags like img or a? \$\endgroup\$ Commented Oct 23, 2018 at 12:41
  • 5
    \$\begingroup\$ <p><p></p> is valid HTML (tag soup). Are you confusing HTML with XML? \$\endgroup\$
    – nwellnhof
    Commented Oct 23, 2018 at 13:49
  • 1
    \$\begingroup\$ By specifying HTML I'm assuming that you do not care about significant whitespace? <foo></foo> can be meaningfully different than <foo>\n</foo> if we're just talking about XML in general. \$\endgroup\$
    – Poke
    Commented Oct 23, 2018 at 13:52
  • 1
    \$\begingroup\$ @edc65: This question is not about xhtml \$\endgroup\$
    – recursive
    Commented Oct 23, 2018 at 20:54
  • 1
    \$\begingroup\$ @LuisfelipeDejesusMunoz You can add a rule "Each tag that is not self-closing has a matching (open/close) tag", regarding <p><p></p>. \$\endgroup\$
    – user202729
    Commented Oct 24, 2018 at 15:12

5 Answers 5

1
\$\begingroup\$

Retina, 101 bytes

L`<.*?>
T`¶`_`<(.+)¶</\1
^.+
$&/
{`(( *)((?!.*(</|/>)))?.+)/¶(.+)
$1¶$2$#3*4* $5/
    (</.+>/)
$1
/$

Try it online! Explanation:

L`<.*?>

List just the tags.

T`¶`_`<(.+)¶</\1

Join matching pairs of tags.

^.+
$&/

Add a marker to the end of the first line.

{`(( *)((?!.*(</|/>)))?.+)/¶(.+)
$1¶$2$#3*4* $5/

Copy the indentation from each line to the next, adding 4 spaces if the current line is an opening tag.

    (</.+>/)
$1

But if the next line (which is now the current line) is a closing tag then delete 4 spaces.

/$

Delete the marker once it reaches the last line.

\$\endgroup\$
0
\$\begingroup\$

Python 2, 170 bytes

def f(o,i=-4):
 s,c,n,h,l=" <\n  "
 for t in"".join(o.split()).split(c):
	if'/'==t[:1]:i-=4;h+=(n+i*s)*(l!=t[1:])+c+t
	else:h+=n+i*s+c+t;i+=4-4*('/'in t);l=t
 print h[4:]

Try it online!

\$\endgroup\$
1
  • 1
    \$\begingroup\$ This removes the space between img and src in <img src="hey"/> \$\endgroup\$ Commented Oct 24, 2018 at 23:41
0
\$\begingroup\$

Python 2, 174 bytes

import re
def F(I):
 m=x=0
 n,s,b='\n/<'
 for d in re.findall(r'<(.*?>)',I):
	if d[0]==s:print(n+' '*~-m*4)*x+b+d,;m-=1;x=1
	else:print n+' '*m*4+b+d,;x*=s in d;m+=not s in d

Try it online!

\$\endgroup\$
0
\$\begingroup\$

JavaScript 115 Bytes

s=>(n=c=-1,m=f=>"\n"+" ".repeat(4*c)+f,s.replace(/<\/?|\/>/g,w=>w[1]?(n?k=m(w):k=w,n=1,c--,k):m(w,n=0*c++)).trim())

I lost the original code so whoops no explanation on this one. It's short though so think of it as a reversing challenge :)

Adds some newlines, but it is correctly tabbed.

\$\endgroup\$
0
\$\begingroup\$

PHP, 141bytes

preg_match_all("%(<.*>)%U",$argn,$m);foreach($m[1]as$t)echo!$p|($p=$t[1]!="/")?str_pad("\n",($t[-2]!="/"?$p?++$i:$i--:$i+!$p=0)*4-3):!$i--,$t;

Run as pipe with -nR or try it online.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.