Скобки в сноски

29

Задний план

Программисты LISP покорили мир! Скобки были объявлены как священные символы, и теперь они могут использоваться только в программах LISP. Было решено, что скобки в литературных произведениях должны быть заменены сносками, и ваша задача автоматизировать это для упрощенного текста уценки.

вход

Ваш ввод представляет собой одну строку, содержащую буквенные символы ASCII, пробелы и специальные символы ,.!?(). Он не будет содержать новых строк или цифр. Скобки будут правильно сопоставлены.

Выход

Вы должны преобразовать каждую соответствующую пару скобок во входной строке в сноску. Это происходит следующим образом:

  1. Замените первую подходящую пару скобок и подстроку между ними на порядковый номер, который начинается с 1тегов Markdown <sup>и </sup>.
  2. Добавить в конец строки
    • две новые строки,
    • тег уценки <sub>,
    • число с шага 1,
    • пространство,
    • подстрока между скобками, и
    • закрывающий тег </sub>, в этом порядке.
  3. Если в строке остались скобки, перейдите к шагу 1.

Ваш вывод - полученная строка, возможно, с завершающим переводом строки. Вам не нужно реализовывать этот точный алгоритм, если ваш вывод верен. Обратите внимание, что могут быть вложенные скобки; в этом случае у нас будут сноски, которые содержат ссылки на другие сноски. Подстрока между скобками также может быть пустой. Смотрите примеры ниже.

Правила и оценки

Вы можете написать либо полную программу, либо функцию. Побеждает меньшее количество байтов, и стандартные лазейки запрещены.

Если ваш язык изначально не поддерживает десятичные числа ( кашель Retina от кашля ), вы можете дать номера сноски в другой базе, в том числе двоичном или унарный; однако использование одинарных чисел влечет наложение штрафа в размере + 20% .

Тестовые случаи

Входные данные:

This input contains no parentheses.

Выход:

This input contains no parentheses.

Входные данные:

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

Выход:

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

<sub>1 some</sub>

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

Входные данные:

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>

Входные данные:

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

Выход:

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>

Обратите внимание на пустые строки между сносками.

Zgarb
источник
23
Может ли моя программа содержать круглые скобки, даже если она не написана на Лиспе или это наказуемо сейчас?
Мартин Эндер
16
@ MartinBüttner Скобки в программах, не относящихся к LISP, неохотно разрешены, если они используются для большей пользы, например, при преобразовании других скобок в сноски.
Згарб
Может ли ввод состоять из нескольких строк? В этом случае следует ли размещать сноски после каждой строки или в конце? Например, для чего нужен выход foo (bar)\nfoot (note)?
xebtl
@xebtl Ввод всегда в одну строку. Смотрите раздел Входные данные : «Он не будет содержать новых строк или цифр».
Згарб
2
:( @ эта спецификация нумерует сноски в ширину, а не в глубину
Sparr

Ответы:

10

Perl, 81 75 72 байта

71 байт код + 1 байт аргумент командной строки.

Требуется Perl 5.10 или новее (для поддержки рекурсивных регулярных выражений)

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

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

Использование:

perl -p entry.pl input.txt

объяснение

-p Параметр выводит результат применения заданных команд к входу, избегая необходимости явной печати.

Регулярное выражение (\(((?1)|.)*?)\))ищет крайний набор скобок с начала строки. Когда это найдено, мы выполняем замену, гарантируя, что мы добавим только в самом конце ввода (захватывая все до конца ввода, используя (.*)).

Затем мы повторяем подстановку регулярных выражений для теперь замещенной строки, используя redo, что будет постоянно применять подстановку регулярных выражений, пока она не перестанет совпадать. В sМодификатор гарантирует , что .в регулярном выражении будет соответствовать новые линии, что необходимо , потому что мы повторно применить регулярное выражение матч на результат предыдущего замещения регулярных выражений.

Jarmex
источник
1
Вы можете быть в состоянии уйти с с [^)] или даже .вместо [^()]becuase гарантии , что вход будет сбалансирован правильно.
Мартин Эндер
+1 за знакомство с рекурсивными регулярными выражениями :-). Но я думаю, что при строгом чтении задачи это неверно: если строка содержит новые строки, сноски будут размещаться после каждой строки, а не в конце. (См. Мою просьбу о разъяснении выше.)
xebtl
Хороший вопрос @ MartinBüttner - мы можем избежать неприятностей ., сделав матч ленивым. @xebtl, в заявке говорится: «В ней не будет символов новой строки или цифр»
Jarmex,
12

Emacs Lisp, 335 байт

Предисловие. Этот ответ и ответ Схемы в настоящее время являются единственными ответами, официально одобренными как Могучей Народной Республикой ЛИСП, так и Церковью Эмача. Другие ответы, более короткие или нет, считаются угрозой миру. В частности, и с глубоким пренебрежением к любым клеветническим обвинениям в Маккартизме, которые время от времени звучат от враждебных противников государства, мы призываем любого, кто имеет информацию о реальной личности анонимных авторов, пишущих ответы Nonlisp, обращаться в местное бюро. Напоминаем, что каждому следует уделить время на то, чтобы обдумать и выразить свое мнение в соответствии с тем, что, по его глубокому убеждению, не будет угрожать его или ее будущему взаимодействию с официальными представителями действующей власти. Код это данные. Данные это код.

(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>")))))

Более элегантно:

(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>")))))
CoreDump
источник
9

Сетчатка , 96 86 83 байта * 120% = 99,6

Исходный код этого решения состоит из двух файлов:

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

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

объяснение

Это очень прямая реализация алгоритма, описанного в задаче. Код состоит из одной подстановки регулярных выражений, которая превращает первый набор скобок в сноску. Эта замена повторяется через+ до пор, пока строка не перестанет изменяться, что означает, что регулярное выражение больше не соответствует (потому что больше не может найти круглые скобки).

Сноски перечислены в одинарном формате, так что я могу просто найти номер последней сноски и добавить 1 чтобы создать следующую.

Регулярное выражение для нахождения первого набора скобок основано на стандартном методе сопоставления скобок с уравновешивающими группами (hrhr, «сопоставление скобок»). Он был немного сокращен за счет использования неназванной группы и предположения, что круглые скобки правильно сбалансированы (что означает, что мы можем опустить (класс отрицанных символов и сопоставить финал )с простым. и нам также не нужно гарантировать, что стек захвата пуст).

После сопоставления скобок и захвата их содержимого в группу 1, мы собираем остаток строки с помощью (.*)в группу, 4а затем ищем в строке первый набор 1s с отрицательным взглядом сзади. Если мы найдем такую ​​подстроку, мы храним в группе 5. Если мы этого не сделаем, мы посмотрим, что не получится, но это нормально, потому что это необязательно - это просто означает, что $5даст пустую строку, которая является унарным представлением0 и которая также является правильной.

Затем строка подстановки просто объединяет все вместе на основе групп захвата. Номер сноски увеличивается путем добавления 1к последнему номеру с помощью 1$5.

Мартин Эндер
источник
3
Сетчатка на победной полосе!
orlp
@orlp Или это? ;) Балансирующие группы не соответствуют рекурсивным регулярным выражениям. Это и не в состоянии обрабатывать десятичные числа ...
Мартин Эндер
Время украсть PHP-оболочку и внедрить Retina вокруг PCRE:
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳
@ n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ Обычно я предпочитаю балансировать группы, чем рекурсию, но в некоторых случаях последний вариант более лаконичен. Возможно, однажды я переопределю .NET regex для Retina и добавлю некоторые дополнительные функции. ;)
Мартин Эндер
9

Священный JavaScript , 1510 байт

Товарищи-повстанцы, не поддавайтесь их тираническому сносу скобок! Вы должны продолжать! С самого начала программирование было свободным предприятием. Теперь это стало повсеместным проявлением благочестия. Мы должны показать не что иное, как абсолютную боязнь. Поэтому я отбивался!

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

Нет правил против использования священных символов на не-лиспском языке. Нет, совсем нет. (Чуть менее компактно :)

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

Это компилируется в расширенный JavaScript в моем другом ответе . Это шутка подчинения.

Конор О'Брайен
источник
5

Луа, 222 216 204 201 байт

Golfed:

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)

Ungolfed:

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
источник
Разве repeat a,b=l(s,g) ... untill a<1петля не будет короче вашего времени?
Катенькио,
4

Схема, 92 байта

Разочарованные реализацией поиска в ширину в Real Lisp, 1 власть имущие решили принять более прагматичный подход. В конце концов, круглые скобки священны, а скобки - нет. 2

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

1. не слушайте тех еретиков из так называемой «церкви» Emacs!
2. Они не программисты Racket, не так ли?

xebtl
источник
Схема должна называться расколом: говорить, что это «Настоящий Лисп» - это настоящая ересь. И вы говорите, это прагматично ? Этот взлом ответа показывает истинную природу мошенников ;-)
coredump
@coredump А вы бы заявили, что ваш чудовищно нефункциональный ответ на elisp является экземпляром True Lisp? Правда, это может занять немного больше времени, но когда ответ Схемы будет закончен, это будет Правильно!
xebtl
3

Haskell, 210 байт

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#)

Пример использования:

*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>

Как это работает:

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
Ними
источник
2

Схема 533 байта

С отступом:

(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)) 
                             ())
                          ()
                          ()))))

Да, это 533 байта, когда все дополнительные пробелы удалены. Греться в функциональной славе.

Я реализовал более или менее алгоритм в описании: xгруппирует ввод в скобках и fзаменяет первый уровень групп сносками, повторяя до тех пор, пока не останется больше групп. Я уверен, что это можно сделать короче, но я не вижу, как это можно сделать много короче без перехода на другой алгоритм.

Как написано, это полная программа. Вы можете попробовать это здесь , но поскольку repl.it, очевидно, не может справиться с этим, (read-line)вы должны поместить входную строку на место. Абсолютно незагрязненная версия здесь .

РЕДАКТИРОВАТЬ: Как указано в комментариях, я изменил скобки ()в скобках []в версиях repl.it. Это было сделано исключительно для удобства во время программирования и отладки. Версия, опубликованная сейчас, работает с ().

xebtl
источник
1
+1, но я не понимаю, почему вы меняете квадратные скобки. Если я изменю #\[«#]» на соответствующие скобки (и обновлю тесты), это работает без проблем. Есть ли причина, по которой вы оставили квадратные? это связано с вашим предыдущим ответом?
coredump
1
@coredump ты абсолютно прав. Я изменил на квадратные скобки, потому что (a) литералы парных символов испортили совпадение парней repl.it и (b) при отладке, вывод (который будет включать в себя множество паренов из списков) был намного более читаемым с помощью скобок. Тогда я просто оставил это так. Я буду редактировать.
xebtl
1

JavaScript ES6, 244 байта

Серьезный ответ (работает только на FireFox, насколько мне известно)

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)}

Expanded:

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);
}
Конор О'Брайен
источник
0

гания , 315 байт

В настоящее время это неконкурентоспособно, поскольку не совсем подходит и для вложенных.

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);}

Expanded:

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);

}

Яков Мисирян
источник