Paréntesis en notas al pie

29

Fondo

¡Los programadores de LISP se han apoderado del mundo! Los paréntesis se han declarado como caracteres sagrados y, a partir de ahora, solo se pueden usar en programas LISP. Se ha decidido que los paréntesis en las obras literarias se reemplazarán por notas al pie de página, y es su trabajo automatizar esto para un texto simplificado de Markdown.

Entrada

Su entrada es una sola cadena que contiene caracteres alfabéticos ASCII, espacios y caracteres especiales ,.!?(). No contendrá nuevas líneas o dígitos. Los paréntesis coincidirán correctamente.

Salida

Deberá convertir cada par de paréntesis coincidentes en la cadena de entrada en una nota al pie. Esto sucede de la siguiente manera:

  1. Reemplace el primer par de paréntesis coincidentes y la subcadena entre ellos por un número continuo que comience 1, envuelto entre las etiquetas Markdown <sup>y </sup>.
  2. Añadir al final de la cadena
    • dos líneas nuevas
    • la etiqueta Markdown <sub>,
    • el número del paso 1
    • un espacio,
    • la subcadena entre paréntesis y
    • la etiqueta de cierre </sub>, en este orden.
  3. Si aún quedan paréntesis en la cadena, vaya al paso 1.

Su salida es la cadena resultante, posiblemente con una nueva línea final. No tiene que implementar este algoritmo exacto, siempre que su salida sea correcta. Tenga en cuenta que puede haber paréntesis anidados; en ese caso, tendremos notas al pie que contienen referencias a otras notas al pie. La subcadena entre paréntesis también puede estar vacía. Vea los casos de prueba a continuación para ver ejemplos.

Reglas y puntuación

Puede escribir un programa completo o una función. El conteo de bytes más bajo gana, y las lagunas estándar no se permiten.

Si su idioma no admite de forma nativa los números decimales ( tos Retina tos ), puede dar los números de las notas al pie de página en otra base, incluidos binarios o unarios; sin embargo, el uso de números unarios impone una penalización de + 20% .

Casos de prueba

Entrada:

This input contains no parentheses.

Salida:

This input contains no parentheses.

Entrada:

This has (some) parentheses (but not so many).

Salida:

This has <sup>1</sup> parentheses <sup>2</sup>.

<sub>1 some</sub>

<sub>2 but not so many</sub>

Entrada:

This has (nested (deeply (or highly?) nested)) parentheses (and several groups).

Salida:

This has <sup>1</sup> parentheses <sup>2</sup>.

<sub>1 nested <sup>3</sup></sub>

<sub>2 and several groups</sub>

<sub>3 deeply <sup>4</sup> nested</sub>

<sub>4 or highly?</sub>

Entrada:

Hmm()(()(,))  a()((trt)(v( (((((wut)))))(X)(Y)(Z) )!?!?!?!))oooooooo(oooo)oooo

Salida:

Hmm<sup>1</sup><sup>2</sup>  a<sup>3</sup><sup>4</sup>oooooooo<sup>5</sup>oooo

<sub>1 </sub>

<sub>2 <sup>6</sup><sup>7</sup></sub>

<sub>3 </sub>

<sub>4 <sup>8</sup><sup>9</sup></sub>

<sub>5 oooo</sub>

<sub>6 </sub>

<sub>7 ,</sub>

<sub>8 trt</sub>

<sub>9 v<sup>10</sup>!?!?!?!</sub>

<sub>10  <sup>11</sup><sup>12</sup><sup>13</sup><sup>14</sup> </sub>

<sub>11 <sup>15</sup></sub>

<sub>12 X</sub>

<sub>13 Y</sub>

<sub>14 Z</sub>

<sub>15 <sup>16</sup></sub>

<sub>16 <sup>17</sup></sub>

<sub>17 <sup>18</sup></sub>

<sub>18 wut</sub>

Tenga en cuenta las líneas vacías entre las notas al pie.

Zgarb
fuente
23
¿Puede mi programa contener paréntesis incluso si no está escrito en Lisp o es un delito punible ahora?
Martin Ender
16
@ MartinBüttner Los paréntesis en programas que no son LISP están permitidos a regañadientes, siempre que se usen para el bien común, como convertir otros paréntesis en notas al pie.
Zgarb
¿Puede la entrada ser múltiples líneas? En ese caso, ¿se deben colocar notas al pie después de cada línea o al final? Por ejemplo, ¿para qué es la salida foo (bar)\nfoot (note)?
xebtl
@xebtl La entrada siempre es una sola línea. Consulte la sección Entrada : "No contendrá nuevas líneas o dígitos".
Zgarb
2
:( @ esta especificación numerando notas al pie primero en ancho en lugar de primero en profundidad
Sparr

Respuestas:

10

Perl, 81 75 72 bytes

Código de 71 bytes + argumento de línea de comando de 1 byte.

Requiere Perl 5.10 o más reciente (para soporte de expresiones regulares recursivas)

$i++;s#(\((((?1)|.)*?)\))(.*)#<sup>$i</sup>$4

<sub>$i $2</sub>#s&&redo

Uso:

perl -p entry.pl input.txt

Explicación

-p El parámetro imprimirá el resultado de aplicar los comandos dados a la entrada, evitando la necesidad de una impresión explícita.

La expresión regular (\(((?1)|.)*?)\))busca el conjunto de corchetes más externo desde el comienzo de la cadena. Cuando se encuentra esto, realizamos la sustitución, asegurando que solo agreguemos al final de la entrada (capturando todo hasta el final de la entrada usando (.*)).

Luego repetimos la sustitución de expresiones regulares en la cadena ahora sustituida usando redo, que aplicará continuamente la sustitución de expresiones regulares hasta que ya no coincida. El smodificador asegura que .en la expresión regular coincida con las nuevas líneas, lo cual es necesario porque volvemos a aplicar la coincidencia de expresión regular en el resultado de la sustitución anterior de expresión regular.

Jarmex
fuente
1
Es posible que pueda salirse con la suya [^)] o incluso en .lugar de hacerlo, [^()]debido a la garantía de que la entrada se equilibrará correctamente.
Martin Ender
+1 por presentarme expresiones regulares recursivas :-). Pero creo que en una lectura estricta del desafío esto es incorrecto: si la cadena contiene nuevas líneas, las notas al pie se colocarán después de cada línea en lugar de al final. (Vea mi solicitud de aclaración arriba).
xebtl
Buen punto @ MartinBüttner: podemos escapar .haciendo que el partido sea flojo. @xebtl, el desafío dice "No contendrá nuevas líneas o dígitos"
Jarmex
12

Emacs Lisp, 335 bytes

Prefacio. Esta respuesta y las del Esquema son actualmente las únicas respuestas autorizadas oficialmente tanto por la Poderosa República Popular de LISP como por la Iglesia de Emacs. Otras respuestas, más cortas o no, se consideran una amenaza para la paz. En particular, y con un profundo desdén por cualquier acusación calumniosa de macartismo que se escuche esporádicamente de los opositores hostiles del estado, le pedimos a cualquiera que tenga información sobre la identidad real de los autores anónimos que escriben respuestas Nonlisp que se comuniquen con su Oficina Local. Se recuerda que todos deberían tomarse el tiempo para reflexionar y votar de acuerdo con lo que él o ella cree profundamente que no amenazará sus futuras interacciones con los representantes oficiales del poder en el lugar. El código es datos. Los datos son código.

(defun p()(let(b(cpt 0)n)(goto-char 0)(while(search-forward"("()t)(setf b(point)n(number-to-string(incf cpt)))(backward-char)(forward-sexp)(backward-char)(kill-region b(point))(delete-backward-char 1)(delete-forward-char 1)(insert "<sup>"n"</sup>")(save-excursion(end-of-buffer)(newline 2)(insert "<sub>"n" ")(yank)(insert"</sub>")))))

Más elegantemente:

(defun parens ()
  (let (b(cpt 0)n)
    (goto-char 0)
    (while(search-forward"("()t)
      (setf b(point)n(number-to-string(incf cpt)))
      (backward-char)
      (forward-sexp)
      (backward-char)
      (kill-region b(point))
      (delete-backward-char 1)
      (delete-forward-char 1)
      (insert "<sup>"n"</sup>")
      (save-excursion
       (end-of-buffer)
       (newline 2)
       (insert "<sub>"n" ")
       (yank)
       (insert "</sub>")))))
volcado de memoria
fuente
9

Retina , 96 86 83 bytes * 120% = 99.6

El código fuente de esta solución consta de dos archivos:

+s`\((((\()|(?<-3>\))|[^)])*).(.*)(?<=(1+).*?)?
<sup>1$5</sup>$4

<sub>1$5 $1</sub>

Explicación

Esta es una implementación muy directa del algoritmo como se describe en el desafío. El código consiste en una única sustitución de expresiones regulares que convierte el primer conjunto de paréntesis en una nota al pie. Esta sustitución se repite a través de +hasta que la cadena deja de cambiar, lo que aquí significa que la expresión regular ya no coincide (porque no puede encontrar más paréntesis).

Las notas al pie se enumeran en unario, de modo que simplemente puedo buscar el número de la última nota al pie y agregar a 1para crear el siguiente.

La expresión regular para encontrar el primer conjunto de paréntesis se basa en la técnica estándar para unir paréntesis con grupos de equilibrio (hrhr, "paréntesis coincidentes"). Se ha acortado un poco al usar un grupo sin nombre y al suponer que los paréntesis están correctamente equilibrados (lo que significa que podemos omitir el (de la clase de caracteres negados y hacer coincidir el final )con un simple .y tampoco necesitamos asegurarnos de que el la pila de captura está vacía).

Después de hacer coincidir los paréntesis y capturar su contenido en grupo 1, capturamos el resto de la cadena (.*)en grupo 4y luego buscamos en la cadena el primer conjunto de 1s con una mirada negativa hacia atrás. Si encontramos una subcadena, la almacenamos en grupo 5. Si no lo hacemos, miramos hacia atrás falla, pero está bien porque es opcional, solo significa que $5dará una cadena vacía que es la representación unaria de 0y que también es correcta.

Luego, la cadena de sustitución simplemente une todo en función de los grupos de captura. El número de la nota al pie se incrementa anteponiendo 1a al último número con 1$5.

Martin Ender
fuente
3
¡Retina está en una racha ganadora!
orlp
@orlp ¿O sí? ;) Los grupos de equilibrio no son rival para la expresión regular recursiva. Eso y no ser capaz de manejar números decimales ...
Martin Ender
Es hora de robar el contenedor PHP e implementar Retina alrededor de PCRE:
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳
@ n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ Normalmente, prefiero tener grupos de equilibrio que recurrencia, pero hay algunos casos en los que este último es más conciso. Tal vez algún día vuelva a implementar el sabor de expresión regular .NET para Retina y aplique algunas características adicionales. ;)
Martin Ender
9

JavaScript sagrado , 1510 bytes

¡Compañeros rebeldes, no cedan ante su tiránica demolición del paréntesis! ¡Debes perseverar! Desde el principio, la programación ha sido una empresa libre. Ahora, se ha convertido en un espectáculo impregnado de piedad. Debemos mostrar nada menos que absoluto temor. ¡Por lo tanto, he luchado!

    ( )( (((  ((  )( )  (( ))( )) (( ( ((  ) ( ()( ) (( ) )(( ((( ()((( ) ( ) )((  ) (((((( )( (())((  ) ) )( ()(( ((()((()   ( (  (  ( )) ((  )( ) (( ) )((((  ( () ) )( ( ()(( )( () ((( )(( ) )( ()((( ) ( )  ( )() (((( () ) (((( () ) ((() ) ()  ( (  (  ( )) ( )(  ((((( )) ((  )( ) (( ) )((((  ) )  ()(  ((() ( ()(( ) ( ) )(( ))(((  (( ) ((  ) ( ()(( )( ) ()  ( (  (  ( ()( ) )( ()(  ) ()  ( (  (  ( )( (( ( (( )  ((((( ))  ) )(( )) ((  )( ) (( ) )((((  ) ()( ))  ) ) (( )( () (((   ( ) )((  )( )(((( ))( )() ) ()( ))  (()( (()( ((()((()   ( (  (    (  ( )) ( )(  (((((( )(( ( (( )) ( ((  ) )( ) )( ( )( ((() ( )( ((() ( ()( ()( ()   ) )( ()(( ) ()  ( (  (    (  ( )) ( )(  (((((( )(( ( (( )) ( ((  ) )( ) )( ( )( (((( ( )( ((() ( ()( ()( (()( ) )( ()(( ) ()  ( (  (    (  ( )) ( )(  (((( ( ) ( ()( ((() ( ()( ())(( ) ( ) )( ()(( ))) ) ()  ( (  (  ((())  ( (  (  ((( ( ) )((( )( () ((( )(((   ( )) ( )  ( ) ) ((((( )) ((  )( ) (( ) )((((  (())( ))  (()( ()(( ((()  ( (  (  ( )(  ) )(((( ( () ((( ) ( ) )(( ((((   ( ()(( )  ( ) ) (((( () )( ((( ((((((()( ((() ((   () )( )(( (()) ( )( ( )( ((() ) ()  ( (  (  (( ) ( ) )(( ))(((  (( ) ((  ) ( ()( ) (( ) )(( ((( ()((( ) ( ) )((  ) (((((( )( () ((( ) ( ) )(( ((((   ( ()(( )  ( ) ) ((((((( ( (()) ( )( ) ) (( )((((  ( ()) ) )) ( )( (()(((  ) (()( ( )( ) )  () )(( )((((  ( ()) ) )) ( )( ((() (()( ( )(  ( (  ( ( ) ) (( )((((  ( ()) ) )) ( )( (()(((  ) (()( ( )( ( () ( )( (()(( )(  (()( ( )( ) )  () )(( )((((  ( ()) ) )) ( )( (())((  ) (()( ()(( ((() ) ()  ( (((())

No hay reglas contra el uso de los caracteres sagrados en un lenguaje que no sea Lisp. No para nada. (De una manera un poco menos compacta :)

( )( (((  ((  )( )  (( ))( )) (( ( ((  ) ( ()( ) (( ) )(( ((( ()((( ) 
( ) )((  ) (((((( )( (())((  ) ) )( ()(( ((()((()   ( (  (  ( )) ((  )
( ) (( ) )((((  ( () ) )( ( ()(( )( () ((( )(( ) )( ()((( ) ( )  ( )()
 (((( () ) (((( () ) ((() ) ()  ( (  (  ( )) ( )(  ((((( )) ((  )( ) (
( ) )((((  ) )  ()(  ((() ( ()(( ) ( ) )(( ))(((  (( ) ((  ) ( ()(( )(
 ) ()  ( (  (  ( ()( ) )( ()(  ) ()  ( (  (  ( )( (( ( (( )  ((((( )) 
 ) )(( )) ((  )( ) (( ) )((((  ) ()( ))  ) ) (( )( () (((   ( ) )((  )
( )(((( ))( )() ) ()( ))  (()( (()( ((()((()   ( (  (    (  ( )) ( )( 
 (((((( )(( ( (( )) ( ((  ) )( ) )( ( )( ((() ( )( ((() ( ()( ()( ()  
 ) )( ()(( ) ()  ( (  (    (  ( )) ( )(  (((((( )(( ( (( )) ( ((  ) )(
 ) )( ( )( (((( ( )( ((() ( ()( ()( (()( ) )( ()(( ) ()  ( (  (    (  
( )) ( )(  (((( ( ) ( ()( ((() ( ()( ())(( ) ( ) )( ()(( ))) ) ()  ( (
  (  ((())  ( (  (  ((( ( ) )((( )( () ((( )(((   ( )) ( )  ( ) ) ((((
( )) ((  )( ) (( ) )((((  (())( ))  (()( ()(( ((()  ( (  (  ( )(  ) )(
((( ( () ((( ) ( ) )(( ((((   ( ()(( )  ( ) ) (((( () )( ((( ((((((()(
 ((() ((   () )( )(( (()) ( )( ( )( ((() ) ()  ( (  (  (( ) ( ) )(( ))
(((  (( ) ((  ) ( ()( ) (( ) )(( ((( ()((( ) ( ) )((  ) (((((( )( () (
(( ) ( ) )(( ((((   ( ()(( )  ( ) ) ((((((( ( (()) ( )( ) ) (( )((((  
( ()) ) )) ( )( (()(((  ) (()( ( )( ) )  () )(( )((((  ( ()) ) )) ( )(
 ((() (()( ( )(  ( (  ( ( ) ) (( )((((  ( ()) ) )) ( )( (()(((  ) (()(
 ( )( ( () ( )( (()(( )(  (()( ( )( ) )  () )(( )((((  ( ()) ) )) ( )(
 (())((  ) (()( ()(( ((() ) ()  ( (((())

Esto compila el JavaScript expandido en mi otra respuesta . Esta es una presentación de broma.

Conor O'Brien
fuente
5

Lua, 222 216 204 201 bytes

Golfizado:

s=io.read()g="%b()"c=1k=string l=k.find t=k.sub o=k.format a,b=l(s,g)while a do s=t(s,0,a-1)..o("<sup>%d</sup>",c)..t(s,b+1,#s).."\n\n"..o("<sub>%d %s</sub>",c,t(s,a+1,b-1))c=c+1 a,b=l(s,g)end print(s)

Sin golf:

input=io.read() 
inputFormat="<sup>%d</sup>"
footnoteFormat="<sub>%d %s</sub>"
counter=1
a,b=string.find(input,"%b()")
while a do
    current=string.sub(input,a+1,b-1)
    input=input.."\n\n"..string.format(footnoteFormat, counter, current) 
    input=string.sub(input,0,a-1)..string.format(inputFormat, counter)..string.sub(input,b+1,#input)
    counter=counter+1
    a,b=string.find(input,"%b()")
end

print(input)
Nikolai97
fuente
¿No sería un repeat a,b=l(s,g) ... untill a<1bucle más corto que tu tiempo?
Katenkyo
4

Esquema, 92 bytes

Frustrados con la implementación de la búsqueda de primer orden en Real Lisp, 1 los poderes fácticos deciden adoptar un enfoque más pragmático. Después de todo, los paréntesis son sagrados, pero los paréntesis no lo son. 2

(lambda(s)(list->string(map(lambda(c)(case c((#\()#\[)((#\))#\])(else c)))(string->list s)))

1. ¡no escuches a esos herejes de la llamada "iglesia" de Emacs!
2. No son programadores de Racket, ¿verdad?

xebtl
fuente
El esquema se llamará Cisma: decir que es el "verdadero Lisp" es la herejía real. ¿Y dices que es pragmático ? Este truco de una respuesta muestra la verdadera naturaleza de los intrusos ;-)
coredump
@coredump ¿Y diría que su respuesta elisp monstruosamente no funcional es una instancia de True Lisp? Puede tardar un poco más, es cierto, pero cuando la respuesta del Esquema haya finalizado, ¡será lo correcto!
xebtl
3

Haskell, 210 bytes

n#x|b==""=a|1<2=a++"<sup>"++m++"</sup>"++((n+1)#(c++"\n\n<sub>"++m++' ':init d++"</sub>"))where m=show n;(a,b)=span(/='(')x;(d,c)=[x|x@(y,_)<-map(`splitAt`(tail b))[0..],'('!y<')'!y]!!0;c!l=[1|m<-l,m==c]
p=(1#)

Ejemplo de uso:

*Main> putStrLn $ p "This has (nested (deeply (or highly?) nested)) parentheses (and several groups)."
This has <sup>1</sup> parentheses <sup>2</sup>.

<sub>1 nested <sup>3</sup></sub>

<sub>2 and several groups</sub>

<sub>3 deeply <sup>4</sup> nested</sub>

<sub>4 or highly?</sub>

Cómo funciona:

n # x                      -- # does all the work, n is the current number of the
                           --   footnote and x the input string
  | b=="" = a              -- if b (see below) is empty, there's no ( in the
                           --   string and the result is 'a' (see below)
  | 1<2   = a++"<sup>"++m++"</sup>"++ ((n+1)#(c++"\n\n<sub>"++m++' ':init d++"</sub>"))
                           -- otherwise (b not empty) build the output string
                           --   starting with 'a' and a footnote number and a
                           --   recursive call with the current footnote appended
                           --   to the rest of the string  

  where 
  m = show n;              -- turn n into string
  (a,b) = span (/='(') x;  -- split the input string x into two parts:
                           --   a: everything before the first (
                           --   b: beginning with the first ( to the end
                           --   if there's no (, a is x and b is empty
  (d,c) = [x|x@(y,_)<-map(`splitAt`(tail b))[0..],'('!y<')'!y]!!0;
                           -- find matching ) in the tail of b ('tail' to remove leading '(') 
                           --   d: everything before and including the matching )
                           --   c: everything behind the matching )
  c!l=[1|m<-l,m==c]        -- helper function that builds a list of 1s for every character searched for
                           --   we have reached the matching ) if the list for ( is
                           --   shorter (less than, <) the list for )

p=(1#)                     -- start with footnote 1
nimi
fuente
2

Esquema, 533 bytes

Con sangría:

(letrec ((l string->list)
         (n number->string)
         (? null?)
         (p (lambda (o) (or (pair? o)(? o))))
         (a car)
         (d cdr)
         (e append)
         (i 0)
         (x
          (lambda (h t)
            (if (? h)
                t
                (case (a h)
                  ((#\() 
                   (let ((s (x (d h) ())))
                     (x (a s) (e t (d s)))))
                  ((#\)) (cons (d h) (list t)))
                  (else 
                   (x (d h) (e t (list (a h)))))))))
         (f 
          (lambda (h t F)
            (cond ((? h)
                   (let ((w (e t F)))
                     (if (find p w) (f w()()) w)))
                  ((p(a h))
                   (set! i(+ 1 i))
                   (f (d h)
                      (e t (e (l "<sup>")
                              (l (n i))
                              (l "</sup>")))
                      (e F (e (l "\n\n<sub>")
                              (l (n i))
                              '(#\ )
                              (a h)
                              (l "</sub>")))))
                  (else (f (d h) 
                           (e t (list (a h)))
                           F))))))
  (print (list->string (f (x (l (read-line)) 
                             ())
                          ()
                          ()))))

Sí, esto es 533 bytes cuando se elimina todo el espacio en blanco opcional. Disfruta de la gloria funcional.

Implementé más o menos el algoritmo en la descripción: xagrupa la entrada por paréntesis y freemplaza el primer nivel de grupos por notas al pie, repitiendo hasta que no queden más grupos. Estoy seguro de que se puede acortar, pero no veo cómo se podría acortar mucho sin cambiar a un algoritmo diferente.

Como está escrito, es un programa completo. Puede probarlo aquí , pero como repl.it aparentemente no puede manejarlo (read-line), debe colocar la cadena de entrada en su lugar. Una versión completamente sin golf está aquí .

EDITAR: Como se señaló en los comentarios, cambié los paréntesis ()entre paréntesis []en las versiones repl.it. Esto fue puramente por conveniencia durante la programación y depuración. La versión publicada ahora funciona con ().

xebtl
fuente
1
+1, pero no entiendo por qué cambias los corchetes. Si cambio #\['#] `por el paréntesis respectivo (y pruebas de actualización), esto funciona sin problemas. ¿Hay alguna razón por la que dejaste los cuadrados? ¿está relacionado con tu respuesta anterior?
coredump
1
@coredump tienes toda la razón. Cambié a corchetes porque (a) los literales de caracteres paren estropearon repl.it coincide con paren y (b) en la depuración, la salida (que incluirá muchos parens de las listas) era mucho más legible con corchetes. Entonces lo dejé así. Voy a editar
xebtl
1

JavaScript ES6, 244 bytes

Respuesta seria (solo funciona en Firefox, que yo sepa)

d=(s,n=1)=>{u=s.search(/\(/);if(index<a=0)return s;for(i=index;i<s.length;i++){if(s[i]==")")a-=1;if(s[i]=="(")a+=1;if(!a)break}return d(s.replace(v=s.slice(index,i+1),"<sub>"+n+"</sub>")+`

<sub>`+n+" "+v.replace(/^\(|\)$/g,"")+"</sub>",n+1)}

Expandido:

function deparen(s,n=1){
    index = s.search(/\(/);
    if(index<0) return s;
    a=0;
    for(i=index;i<s.length;i++){
        if(s[i]==")") a-=1;
        if(s[i]=="(") a+=1;
        if(!a) break;
    }
    v=s.slice(index,i+1)
    f=v.replace(/^\(|\)$/g,"");
    return deparen(s.replace(v,"<sub>"+n+"</sub>")+"\n\n<sub>"+n+" "+f+"</sub>",n+1);
}
Conor O'Brien
fuente
0

Hasio , 315 bytes

Actualmente esto no es competitivo ya que esto no maneja exactamente los anidados también.

func main(){i=input();r="";f="";z=1;for(x=0;x<i.length;x++){c=i[Convert.toNumber(Convert.toString(x))];if(c=="("){f+="\n<sub>"+z+" ";for(x++;!(i[Convert.toNumber(Convert.toString(x))]==")");x++){f+=i[Convert.toNumber(Convert.toString(x))];}f+="</sub>\n";z++;r+="<sup>"+z+"</sup>";}else r+=c;}println(r);println(f);}

Expandido:

func main() {
    i = input();
    r = "";
    f = "";
    z = 1;
    for (x = 0; x < i.length; x++) {
            c = i[Convert.toNumber(Convert.toString(x))];
            if (c == "(") {
                    f += "\n<sub>" + z + " ";
                    for (x++; !(i[Convert.toNumber(Convert.toString(x))] == ")"); x++) {
                            f += i[Convert.toNumber(Convert.toString(x))];
                    }
                    f += "</sub>\n";
                    z++;
                    r += "<sup>" + z + "</sup>";
            } else
                    r += c;
    }

    println(r);
    println(f);

}

Jacob Misirian
fuente