括号内为脚注


29

背景

LISP程序员已经占领了世界!括号已被声明为神圣字符,从现在开始,它们只能在LISP程序中使用。已经决定用脚注代替文学作品中的括号,并且为简化Markdown文本而使它自动化是您的工作。

输入值

您的输入是一个包含字母ASCII字符,空格和特殊字符的字符串,.!?()。它将不包含换行符或数字。括号将正确匹配。

输出量

您应将输入字符串中每对匹配的括号转换为脚注。发生这种情况如下:

  1. 将第一个匹配的括号对和括号之间的子字符串替换为一个以数字开头的运行编号,该编号1环绕在Markdown标记<sup>和之间</sup>
  2. 附加到字符串的末尾
    • 两条换行符
    • Markdown标签<sub>
    • 步骤1中的数字
    • 空间,
    • 括号之间的子字符串,以及
    • 结束标记</sub>,按此顺序。
  3. 如果字符串中仍然有括号,请转到步骤1。

您的输出是结果字符串,可能带有尾随换行符。只要您的输出是正确的,就不必实现此精确算法。请注意,可能会有嵌套的括号;在这种情况下,我们的脚注将包含对其他脚注的引用。括号之间的子字符串也可以为空。有关示例,请参见下面的测试案例。

规则和计分

您可以编写完整的程序或函数。最低字节数获胜,并且不允许出现标准漏洞。

如果你的语言本身不支持十进制数(咳嗽视网膜咳嗽),你可能会在另一个基地,包括二进制或一元的注脚号码; 但是,使用一元数会产生+ 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>

注意脚注之间的空线。


23
即使我的程序不是用Lisp编写的,我的程序也可以包含括号吗?
马丁·恩德

16
@Latin程序允许使用非LISP程序中的括号,只要它们用于更大的好处,例如将其他括号转换为脚注即可。
Zgarb 2015年

输入可以是多行吗?在这种情况下,应在每行之后还是末尾添加脚注?例如,输出是foo (bar)\nfoot (note)什么?
xebtl

@xebtl输入始终是一行。请参阅输入部分:“它将不包含换行符或数字。”
Zgarb 2015年

2
:( @此规范编号脚注以广度优先而不是深度优先
Sparr

Answers:


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修改确保.在正则表达式将匹配新的生产线,这是必要的,因为我们重新提出申请上一正则表达式替换的结果,正则表达式匹配。


1
您也许可以放弃[^)] 或什至.代替[^()]保证输入正确平衡的保证。
马丁·恩德

+1为我介绍了递归正则表达式:-)。但是我认为从严格的角度看这是不正确的:如果字符串包含换行符,则脚注将放置在每行之后而不是结尾。(请参阅上面的澄清要求。)
xebtl

好点@MartinBüttner-我们可以.通过使比赛变得懒惰来摆脱困境。@xebtl,挑战指出“它将不包含换行符或数字”
Jarmex 2015年

12

Emacs Lisp,335字节

前言。 该答案和计划答案是LISP强大共和国和Emacs教堂目前官方认可的唯一答案。其他答案,无论简短与否,都被视为对和平的威胁。特别是,对于对麦卡锡主义的任何诽谤性指控都极不屑一顾,该指控是从该州的敌对反对者那里零星听到的,我们禁止任何知道匿名作者真实身份的信息的人,这些匿名作者写着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>")))))

9

视网膜96个 86 83字节×120%= 99.6

此解决方案的源代码包含两个文件:

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

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

说明

这是挑战中所述算法的非常直接的实现。该代码由单个正则表达式替换组成,该替换将第一组括号转换为脚注。+直到字符串停止更改为止,都会重复进行此替换,这意味着正则表达式不再匹配(因为它找不到更多的括号)。

脚注一元枚举,因此我可以简单地查找最后一个脚注的编号并添加一个1以创建下一个脚注。

查找第一组括号的正则表达式基于将括号与平衡组进行匹配的标准技术(hrhr,“匹配括号”)。通过使用一个未命名的组并假设括号正确地平衡,它已被缩短了一点(这意味着我们可以(从否定的字符类中省略该字符,并)以一个简单的字符匹配最后一个字符,.并且我们也不必确保捕获堆栈为空)。

在匹配括号并将它们的内容捕获到group中之后1,我们将string的其余部分捕获(.*)为group 4,然后在字符串中搜索1带有负向后的s 的第一组。如果找到这样的子字符串,则将其存储在group中5。如果不这样做,我们将向后寻找失败,但这没关系,因为它是可选的-这仅表示$5将给出一个空字符串,该字符串是的一元表示形式,0也是正确的。

然后,替换字符串会根据捕获组将所有内容简单地组合在一起。通过1在末尾加a 来增加脚注编号1$5


3
视网膜正在取得胜利!
orlp

@orlp还是?;)平衡组与递归正则表达式不匹配。那并不能处理十进制数字...
Martin Ender

现在是时候窃取PHP包装程序并在PCRE周围实现Retina了:
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

@ n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳通常,我宁愿有平衡组而不是递归,但是在某些情况下,后者更为简洁。也许有一天,我将为Retina重新实现.NET regex风格,并修补一些其他功能。;)
Martin Ender 2015年

9

神圣的JavaScript,1510字节

同胞叛军,不要屈服于他们对括号的强暴拆除!你必须坚持不懈!从一开始,编程就是一个免费的企业。现在,它已成为一种普遍的虔诚表现。我们必须表现出绝对的恐惧。因此,我进行了反击!

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

没有禁止在非Lisp语言中使用神圣字符的规则。不,一点也不。(以不太紧凑的方式:)

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

这将编译为我的其他答案中扩展的JavaScript 。这是一个笑话。


5

Lua中,222个 216 204 201字节

打高尔夫球:

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)

取消高尔夫:

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)

不会一repeat a,b=l(s,g) ... untill a<1环是比你而较短的?
Katenkyo,2016年

4

方案,92字节

对于在Real Lisp中实施广度优先的搜索1感到沮丧,因此决定采用一种更务实的方法的权力。毕竟,括号是神圣的,但括号不是。2

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

1.不要听从Emacs所谓的“教会”的异端!
2.他们不是Racket程序员,对吗?


方案应称为分裂:称其为“ Real Lisp”是实际的异端。而你说这很实用?这个答案说明了计划者的真实本性;-)
coredump

@coredump并且您会声称您无法正常工作的elisp答案是True Lisp的一个实例?这可能需要更长的时间,这是正确的,但是当Scheme答案完成后,它将是正确的事情!
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版本。这纯粹是为了方便编程和调试。现在发布的版本可用于()


1
+1,但我不明白为什么要更改方括号。如果我#\[通过相应的括号(和更新测试)来更改'#]`,则可以正常工作。你有理由离开广场吗?与您以前的答案有关吗?
coredump

1
@coredump,您绝对正确。我将括号更改为括号,因为(a)括号中的字符文字使repl.it的括号匹配变得混乱,并且(b)在调试,输出(将包括列表中的很多括号)输出时,括号的可读性更高。然后我就这样离开了。我会编辑。
xebtl 2015年

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

展开:

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

展开:

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

}

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.