脚注への括弧


29

バックグラウンド

LISPプログラマーが世界を席巻しました!括弧は神聖な文字として宣言されており、今後はLISPプログラムでのみ使用できます。文学作品のカッコは脚注に置き換えられることが決定されており、これを自動化してマークダウンテキストを簡素化することがあなたの仕事です。

入力

入力は、アルファベットのASCII文字、スペース、および特殊文字を含む単一の文字列,.!?()です。改行や数字は含まれません。括弧は正しく一致します。

出力

入力文字列内の一致した括弧の各ペアを脚注に変換します。これは次のように発生します。

  1. 括弧の最初の一致するペアとそれらの間の部分文字列1を、Markdownタグ<sup>との間でラップされた開始番号で置き換える</sup>
  2. 文字列の最後に追加
    • 2つの改行、
    • Markdownタグ<sub>
    • ステップ1の番号
    • スペース、
    • 括弧の間の部分文字列、および
    • 終了タグ</sub>、この順序で。
  3. 文字列にまだ括弧が残っている場合は、手順1に進みます。

出力は結果の文字列であり、末尾に改行が含まれる場合があります。出力が正しい限り、この正確なアルゴリズムを実装する必要はありません。括弧がネストされている場合があることに注意してください。その場合、他の脚注への参照を含む脚注があります。括弧の間の部分文字列も空にすることができます。例については、以下のテストケースを参照してください。

ルールとスコアリング

完全なプログラムまたは関数のいずれかを作成できます。最小のバイトカウントが優先され、標準の抜け穴は許可されません。

ご使用の言語が10進数をネイティブにサポートしていない場合( 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>

脚注間の空行に注意してください。


23
Lispで書かれていなくても、プログラムに括弧を含めることはできますか、それとも今では罰せられる犯罪ですか?
マーティンエンダー

16
@MartinBüttner非LISPプログラムの括弧は、他の括弧を脚注に変換するなど、より良い目的で使用される限り、しぶしぶ許可されます。
ズガルブ

入力は複数行にできますか?その場合、脚注を各行の後に、または最後に配置する必要がありますか?たとえば、出力はfoo (bar)\nfoot (note)何ですか?
xebtl

@xebtl入力は常に単一行です。入力セクションを参照してください:「改行や数字は含まれません。」
ズガルブ

2
:( @この仕様の番号付け脚注は、深さ優先ではなく幅優先
15

回答:


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

12

Emacs Lisp、335バイト

序文。 現在、この回答とスキームの回答は、LISPのマイティポピュラーリパブリックとEmacs教会の両方によって公式に認可されている唯一の回答です。他の回答は、短くても短くても、平和への脅威と見なされます。特に、州の敵対的な反対者から散発的に聞かれるマッカーシズムの名誉棄損の申し立てに対する深い軽daにより、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

このソリューションのソースコードは2つのファイルで構成されています。

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

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

説明

これは、チャレンジで説明したように、アルゴリズムの非常に直接的な実装です。このコードは、括弧の最初のセットを脚注に変える単一の正規表現置換で構成されています。この置換は+、文字列の変更が停止するまでを介して繰り返されます。これは、正規表現が一致しなくなることを意味します(これ以上括弧が見つからないため)。

脚注は単項式で列挙されているため、最後の脚注の番号を探して、次の脚注1を作成するためにa を追加するだけです。

括弧の最初のセットを見つけるための正規表現は、平衡化グループと括弧を一致せる標準的な手法(hrhr、「一致する括弧」)に基づいてます。名前のないグループを使用し、括弧が正しくバランスしていると仮定することで少し短縮されました(つまり(、否定文字クラスから省略)し、単純文字列と最終文字列を一致させることができます。.また、キャプチャスタックが空です)。

括弧に一致し、グループにその内容をキャプチャした後1、我々は、と文字列の残りの部分を捕捉(.*)基に4した後の最初のセットの文字列を通って戻る検索1負後読みとS。そのような部分文字列が見つかった場合、groupに格納し5ます。そうしないと、後読みは失敗しますが、それはオプションなので大丈夫です-それは単に$5、単項表現で0あり、正しい空の文字列を与えることを意味します。

置換文字列は、キャプチャグループに基づいてすべてを単純につなぎ合わせます。脚注番号は1、最後の番号の前にa を付加することにより増加し1$5ます。


3
Retinaは連勝中です!
orlp

@orlpそれともそうですか?;)バランシンググループは、再帰的正規表現に一致しません。小数点以下の数字を扱うことができないことと...
マーティン・エンダー

PHPラッパーを盗み、RetinaをPCREに実装する時間:
n –h̴̖̋a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

@ n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳通常、再帰よりもバランスのとれたグループが欲しいですが、後者の方が簡潔な場合もあります。たぶん、いつかRetina用の.NET正規表現フレーバーを再実装し、いくつかの追加機能をパッチするでしょう。;)
マーティン・エンダー

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ループはあなたのwhileよりも短くありませんか?
かてんきょう

4

スキーム、92バイト

Real Lispに幅優先の検索を実装することに不満を抱き、1より強力なアプローチでより実用的なアプローチをとることに決めました。結局、括弧は神聖ですが、括弧はそうではありません。2

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

1. Emacsのいわゆる「教会」からの異端者に耳を傾けないでください!
2.ラケットプログラマーではありませんか?


スキームはSchismと呼ばれます:それが「本当のLisp」であると言うことは実際の異端です。そして、あなたはそれが実用的だと言いますか?この回答のハックは、計画者の本質を示しています;-)
coredump

@coredumpそして、ひどく機能しないelispの答えはTrue Lispのインスタンスであると主張しますか?少し時間がかかるかもしれませんが、Schemeの回答が終了すると、The Right Thingになります!
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、しかし、角括弧を変更する理由がわかりません。#\[それぞれの括弧で '#] ` を変更する(およびテストを更新する)場合、これは問題なく機能します。あなたが正方形のものを残した理由はありますか?それはあなたの以前の答えに関連していますか?
コアダンプ

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

拡張:

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

}

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.