///を解釈する(「スラッシュ」と発音)


30

難解な言語のゴルフを十分に得ることができないので、できますか?

/// —発音のスラッシュ ——Perlのs///名声の正規表現置換機能に基づいた楽しい小さな言語です。スラッシュ/とバックスラッシュの2つの特殊文字のみが含まれています\esolangs wikiで完全な記事を見つけることができますが、以下の言語の説明といくつかの例を再現します。

つまり、/pattern/repl/restプログラムで識別し、可能な限り何度も置換を行うことで機能します。いいえ文字は除いて特別ではない/\/画定パターンや交換プログラムで、しばらくは\リテラルを挿入することを可能にする/か、\あなたのコードに文字を。特に、これらは正規表現ではなく、単なる文字列の置換です。

あなたの課題は、できるだけ少ない文字で、STDINを読み取るプログラムまたは文字列引数を取る関数として、///言語のインタープリターを作成することです。

///自体以外の任意の言語を使用できます。///;を解釈するライブラリは使用できません。ただし、正規表現、正規表現ライブラリ、または文字列一致ライブラリを使用できます。


実行

4つの状態、printpatternreplacement、およびsubstitutionがあります。置換を除くすべての状態で:

  • プログラムが空の場合、実行は停止します。
  • それ以外の場合、最初の文字がの場合、\次の文字(存在する場合)で何かを実行し、プログラムから両方を削除します。
  • それ以外の場合、最初の文字がの場合、/それを削除し、次の状態に変更します。
  • それ以外の場合は、最初の文字で何かをして、プログラムから削除します。
  • 繰り返す。

状態は、printpatternreplacement、およびsubstitutionを順に循環します

  • では、印刷モード、文字手段の出力「何かを行います」。
  • では、パターンモードで、「何かをする」という意味は、現在のパターンに文字を追加します。
  • 代替モードで、「何かをする」という意味では、現在の交換に文字を追加します。

置換モードでは、ルールの異なるセットに従ってください。置換が不可能になるまで、現在のパターンの最初の出現をプログラムの現在の置換で繰り返し置換します。その時点で、パターンと置換をクリアし、印刷モードに戻ります。

プログラム/foo/foobar/foo foo fooでは、次のことが起こります。

/foo/foobar/foo foo foo
foo foo foo
foobar foo foo
foobarbar foo foo
foobarbarbar foo foo
...

これは永久にループし、置換モードを終了しません。同様に、パターンが空の場合、プログラムの先頭にある最初の空の文字列は常に一致するため、置換モードは永久にループし、停止することはありません。


no

出力:no

/ world! world!/Hello,/ world! world! world!

出力:Hello, world!

/foo/Hello, world!//B\/\\R/foo/B/\R

出力:Hello, world!

a/ab/bbaa/abb

出力:a。プログラムは停止しません。

//

出力:なし。

///

出力:なし。プログラムは停止しません。

/\\/good/\/

出力:good

試してみることができるwikiにも馬があります


/-/World//--/Hello//--W/--, w/---!愛してはいけないことは何ですか?(最後からダッシュを削除してみてください)
seequ 14

@Loovjo \ 文字は、/後に続く文字をエスケープします。これには、後で通常どおり使用できるものも含まれます。これはあまり見かけませんが、/// Turing-completeになります。
algorithmshark

これはesolangsのwiki記事よりも言語のより良い説明だと思います。///私が作成しているIDEでこの情報を使用します!
clabe45

回答:


7

APL(133)

{T←''∘{(0=≢⍵)∨'/'=⊃⍵:(⊂⍺),⊂⍵⋄(⍺,N⌷⍵)∇⍵↓⍨N←1+'\'=⊃⍵}⋄⍞N←T⍵⋄p N←T 1↓N⋄r N←T 1↓N⋄''≡N:→⋄∇{⍵≡p:∇r⋄∨/Z←p⍷⍵:∇(r,⍵↓⍨N+≢p),⍨⍵↑⍨N←1-⍨Z⍳1⋄⍵}1↓N}

これは、///正しい引数としてコードを受け取る関数です。

Ungolfed、説明付き:

slashes←{
   ⍝ a function to split the input string into 'current' and 'next' parts,
   ⍝ and unescape the 'current' bit
   split←''∘{
       ⍝ if the string is empty, or '/' is reached,
       ⍝ return both strings (⍺=accumulator ⍵=unprocessed)
       (0=≢⍵)∨'/'=⊃⍵:(⊂⍺),⊂⍵
       ⍝ otherwise, add current character to accumulator,
       ⍝ skipping over '\'s. (so if '\/' is reached, it skips '\',
       ⍝ adds '/' and then processes the character *after* that.)
       idx←1+'\'=⊃⍵
       (⍺,idx⌷⍵)∇idx↓⍵
   }

   ⍞   next ← split ⍵      ⍝ output stage
   pat next ← split 1↓next ⍝ pattern stage, and eat the '/'
   rpl next ← split 1↓next ⍝ replacement stage, and eat the '/'

   ⍝ if there are no characters left, halt.
   ''≡next:⍬

   ⍝ otherwise, replace and continue.
   ∇{  ⍝ if the input string equals the pattern, return the replacement and loop
       ⍵≡pat:∇rpl

       ⍝ otherwise, find occurences, if there are, replace the first and loop
       ∨/occ←pat⍷⍵:∇(rpl, (idx+≢pat)↓⍵),⍨ (idx←(occ⍳1)-1)↑⍵

       ⍝ if no occurences, return string
       ⍵

   }1↓next
}

「文字が残っていない場合、停止します。」これは///andで正しく動作しますか//foo/(つまり、永久にループしますか)?
algorithmshark

@algorithmshark:はい、その状況/では、その時点でまだ残っています。
マリヌス14

11

J - 181 190 170 CHAR

これは悪夢でした。それはただ私を悩ませ続けたので、私はそれを二度ゼロから書き直しました。これは、単一の文字列引数を取り、STDOUTに出力する関数です。

(0&$`((2{.{:@>&.>)((j{.]),-i@=`p@.~:~/@[,]}.~#@p+j=.0{p I.@E.])i 5;@}.&,'/';"0;&.>)@.(2<#)@}.[4:1!:2~{:@>@p=.>@{.@[)@((0;(0,:~1 0,.2);'\';&<1 0)<;._1@;:'/'&,)i=. ::](^:_)

説明するために、サブ表現に分割します。

i =. ::](^:_))
parse =: ((0;(0,:~1 0,.2);'\';&<1 0)<;._1@;:'/'&,)
print =: 4:1!:2~{:@>@p=.>@{.@[
eval  =: 0&$`((2{.{:@>&.>)sub 5;@}.&,'/';"0;&.>)@.(2<#)@}.
sub   =: ((j{.]),-i@=`p@.~:~/@[,]}.~#@p+j=.0{p I.@E.])i

interp =: (eval [ print) @ parse i
  • iiterateの略)は副詞です。左側の動詞引数を取り、動詞を返します。この動詞(f)iは、引数に適用さfれると、固定小数点(y = f y)が見つかるか、エラーがスローされるまで、引数に繰り返し適用されます。固定小数点の動作はに固有^:_であり::]、エラー処理を行います。

  • parse入力を半解析形式と呼ぶものにトークン化し、エスケープされていない「/」で切り取ります。エスケープされたバックスラッシュをキャラクターにバインドしますが、バックスラッシュを取り除きません。したがって、必要に応じて元に戻すか終了することができます。

    興味深い作品の大部分はで発生し;:ます。これはシーケンシャルマシンインタープリタープリミティブで(0;(0,:~1 0,.2);'\';&<1 0)、左側にマシン()の説明を、右側に解析対象を記述します。これはトークン化を行います。この特定のマシンは、実際に最初の文字を特別なものとして扱い\ます。これにはいくつかの理由があります。(1)状態テーブルが単純なので、さらにゴルフをすることができます。(2)問題を回避するために、ダミー文字を前面に簡単に追加できます。(3)ダミー文字は追加費用なしで半分解析されるので、次にそれを使用して切断フェーズのセットアップを行うことができます。

    また<;._1、エスケープされていないトークン化された結果をカットするために使用し/ます(これが最初の文字になります)。これは、out/patt/repl/restすべての出力、パターン、置換を1つのステップで引き出すのに便利ですが、残念なことに、プログラムの残りの部分もカットさ/れます。私は中にこれらのバックスプライスeval作るので、<;._1より多くの原価計算任せるそれらだけで終了します。

  • fork (eval [ print)printparse副作用の結果に対して実行され、実行されますevalprintは単純な動詞で、最初のボックス(確かに出力が確認されているボックス)を開き、解析を終了して、STDOUTに送信します。ただし、ユーティリティ動詞を定義することもできますp

    pはとして定義されている>@{.@[ので、その左引数(引数を1つだけ指定した場合はIDのように動作します)、その最初の項目(スカラーを指定した場合はID)を取得し、それをアンボックスします(すでにボックス化されていない場合はアイデンティティ)。これは非常に便利ですsub

  • eval処理されたプログラムの残りを評価します。完全なパターンまたは完全な置換がない場合、evalそれをスローし、空のリストを返すだけです。これは、次の反復で;:(from parse)エラーを出すことで評価を終了します。そうでない場合evalは、パターンと置換を完全に解析し、ソースの残りを修正してから、両方をに渡しsubます。爆発により:

                                                  @}.  NB. throw out printed part
                                           @.(2<#)     NB. if we have a pattern and repl:
          2{.                                          NB.  take the first two cuts:
                 &.>                                   NB.   in each cut:
             {:@>                                      NB.    drop escaping \ from chars
         (          )                                  NB.  (these are pattern and repl)
                                       &.>             NB.  in each cut:
                                      ;                NB.   revert to source form
                                '/';"0                 NB.  attach a / to each cut
                              &,                       NB.  linearize (/ before each cut)
                         5  }.                         NB.  drop '/pattern/repl/'
                          ;@                           NB.  splice together
        (            sub                  )            NB.  feed these into sub
       `                                               NB. else:
    0&$                                                NB.  truncate to an empty list
    
  • sub置換の1つの(無限の可能性がある)ラウンドが発生する場所です。設定方法evalにより、ソースは正しい引数であり、パターンと置換は左側にまとめられています。引数はこのように順序付けられており、パターンと置換が置換のラウンド内で変更されないことがわかっているため、別の機能を使用することができますi-正しい引数のみを変更し、同じ左に渡し続けるという事実- Jに状態の追跡を心配する必要性。

    ただし、2つの問題点があります。1つ目は、J動詞は最大2つの引数を持つことができるため、ここではパターンや置換など、一緒にバンドルされているものにアクセスする簡単な方法がないことです。p定義したユーティリティを賢く使用することで、これはそれほど大きな問題ではありません。実際に、私達はちょうど使用することにより、一つの文字パターンにアクセスすることができp、そのにより、>@{.@[左の引数の最初の項目のVHS版:定義。代替品を入手するのは難しいですが、最短の方法はp&|.、手動で交換するよりも2文字短くなります。

    2番目の問題は、i永久にループするのではなく固定小数点で終了することです。パターンと置換が等しく、置換を行うと、Jに対する固定小数点のように見えます。1を否定する無限ループに入り、それらが等しいことを検出した場合:これは-i@=`p@.~:~/、を置き換える部分p&|.です。

                                        p    E.]    NB. string search, patt in src
                                          I.@       NB. indices of matches
                                      0{            NB. take the first (error if none)
                                   j=.              NB. assign to j for later use
                               #@p+                 NB. add length of pattern
                           ]}.~                     NB. drop that many chars from src
                       /@[                          NB. between patt and repl:
                      ~                             NB.  patt as right arg, repl as left
                  @.~:                              NB.  if equal:
            -i@=                                    NB.   loop forever
                `p                                  NB.  else: return repl
     (j{.])                                         NB. first j chars of src
           ,              ,                         NB. append all together
    (                                           )i  NB. iterate
    
  • このサイクルは、の使用によりisubエラー以外の何かがなくなるまで繰り返されます。私が知っている限りでは、これはキャラクターが不足しているとき、またはパターンと置換の不完全なセットを捨てるときにのみ起こります。

このゴルフの楽しい事実:

  • 一度使用する;:と、文字列を手動で反復するよりも短くなります。
  • 0{sub無限ループに入る前にエラーが発生する可能性があるため、パターンが置換に一致してもソースの残りに表示されない場合は正常に動作するはずです。ただし、ドキュメントで引用を見つけることができないため、これは不特定の動作である場合とそうでない場合があります。おっと。
  • キーボード割り込みは、実行中の機能内で自発的なエラーとして処理されます。ただし、の性質によりi、これらのエラーもトラップされます。Ctrl + Cを押すタイミングに応じて、次のことができます。
    • sub無限否定ループを終了し、数値を文字列に連結しようとすることでループからエラーを出し、文字列をそれ自体で無限に置換し終えたかのように///を解釈し続けます。
    • sub中途半端のままにして、半サブブの///式の解釈に進みます。
    • インタプリタから抜け出し、未評価の///プログラムをREPLに返します(ただし、STDOUTではありません)。

使用例:

   f=:(0&$`((2{.{:@>&.>)((j{.]),-i@=`p@.~:~/@[,]}.~#@p+j=.0{p I.@E.])i 5;@}.&,'/';"0;&.>)@.(2<#)@}.[4:1!:2~{:@>@p=.>@{.@[)@((0;(0,:~1 0,.2);'\';&<1 0)<;._1@;:'/'&,)i=. ::](^:_)
   f 'no'
no
   f '/ world! world!/Hello,/ world! world! world!'
Hello, world!
   f '/foo/Hello, world!//B\/\\R/foo/B/\R'
Hello, world!
   f '//'  NB. empty string

   f '/\\/good/\/'
good

ワオ。私はこれを自虐的と呼びます。+1
seequ 14

これを実行すると、すべてのテストケースから空の文字列が取得されます。私はjqt64を使用していますが、これを実行するために何を使用していますか?
bcsb1001

@ bcsb1001(64ビット)jconsoleバイナリを直接使用しています。ここでjqtを確認すると、/\\/good/\/テストケースを除いて実際に意図した結果が得られています。1!:2&4jqtにはstdin / outがないため、デバッグにより、問題はを使用していることがわかります。調査します。あなたのどのようなもの9!:12''とは9!:14''
algorithmshark

@algorithmshark私9!:12''は6 歳で、9!:14''j701 / 2011-01-10 / 11:25です。
bcsb1001

4

Perl-190

$|=1;$/=undef;$_=<>;while($_){($d,$_)=/(.)(.*)/;eval(!$e&&({'/','$a++','\\','$e=1'}->{$d})||('print$d','$b.=$d','$c.=$d')[$a].';$e=0');if($a==3){while($b?s/\Q$b/$c/:s/^/$c/){}$a=0;$b=$c=''}}

///EOFまで標準入力からプログラムを読み取ります。


m/^(.*?)(?<!\\)\/(.*?)(?<!\\)\/(.*?)(?<!\\)\/(.*)$/sつまり、出力、パターン、および置換をすべて一度に一致させるというアプローチに沿ったアプローチは、より短いゴルフを実現するでしょうか?私自身、Perlを知りません。
algorithmshark 14

私は、これは失敗したと信じている/a/\0/a
Asone Tuhid

3

ピップ100 102バイト

私はPipがチューリング完全であることをこれまでに証明していませんでした(明らかにそうです)が、BFの通常のルートを行く代わりに、///が面白いと思いました。解決策が得られたら、ゴルフをして、ここに投稿すると思いました。

101バイトのコード、-rフラグの場合は+1 :

i:gJnf:{a:xW#i&'/NE YPOia.:yQ'\?POiya}W#iI'\Q YPOiOPOiEIyQ'/{p:VfY0s:VfIyQ'/WpNi&YviR:Xp{++y?ps}}E Oy

たくさんのコメントを付けた私のバージョンは次のとおりです。

; Use the -r flag to read the /// program from stdin
; Stdin is read into g as a list of lines; join them on newline and assign to c for code
c : gJn

; Loop while c is nonempty
W #c {
 ; Pop the first character of c and yank into y
 Y POc
 ; If y equals "\"
 I yQ'\
  ; Pop c again and output
  O POc
 ; Else if y equals "/"
 EI yQ'/ {
  ; Build up pattern p from empty string
  p : ""
  ; Pop c, yank into y, loop while that is not equal to "/" and c is nonempty
  W #c & '/ NE Y POc {
   ; If y equals "\"
   I yQ'\
    ; Pop c again and add that character to p
    p .: POc
   ; Else, add y to p
   E p .: y
  }

  ; Yank 0 so we can reliably tell whether the /// construct was completed or not
  Y0
  ; Build up substitution s from empty string
  s : ""
  ; Pop c, yank into y, loop while that is not equal to "/" and c is nonempty
  W #c & '/ NE Y POc {
   ; If y equals "\"
   I yQ'\
    ; Pop c again and add that character to s
    s .: POc
   ; Else, add y to s
   E s .: y
  }

  ; If the last value yanked was "/", then we have a complete substitution
  ; If not, the code must have run out; skip this branch, and then the outer loop
  ; will terminate
  I yQ'/ {
   ; While pattern is found in code:
   W pNc {
    ; Set flag so only one replacement gets done
    i : 0
    ; Convert p to a regex; replace it using a callback function: if ++i is 1,
    ; replace with s; otherwise, leave unchanged
    c R: Xp {++i=1 ? s p}
   }
  }
 }
 ; Else, output y
 E Oy
}

オンラインでお試しください!(プログラムが終了していない場合、TIOは何も出力せず、時間制限もあります。より大きな例と無限ループの場合、コマンドラインからPipを実行することをお勧めします。)


私はこれがあるべきだと思うpip + -r、101バイト
Asone Tuhid

3

C ++:Visual C ++ 2013 = 423、g ++ 4.9.0 = 442

これは決して勝てませんが、将来のソフトウェアプロジェクトはすべてこの素晴らしい言語で書かれることを決めたので、そのための通訳者が必要でした。

スコアの違いは、Visual C ++は最初のインクルードを必要としないが、g ++は必要なことです。スコアは、行末が1としてカウントされることを想定しています。

#include<string.h>
#include<string>
#define M(x)memset(x,0,99);
#define P o[i])
#define N(x)P;else if(n<x)(P==92?
#define O (o[++i]):(P==47?n++:
#define S std::string
int main(int n,char**m){S o=m[1];char p[99],*q=p,r[99],*s=r;M(p)M(r)for(int i=0,t;i<=o.size();++i){if(!N(3)putchar O putchar(N(4)*q++=O(*q++=N(5)*s++=O(*s++=P;if(n>4){for(;;){if((t=o.find(p,i+1))==S::npos)break;o=o.substr(0,t)+r+o.substr(t+strlen(p));}M(p)M(r)n=2;q=p;s=r;}}}

1
あなたは書き換えることができるif(!o[i]);ようにif(P文字を保存するために、またはの#defineがどのように動作するか私は誤解ですか?
algorithmshark 14

@algorithmsharkどうしてそれを見逃したのですか?!!場合(Pは完璧です、私はそれを変更します。。
ジェリーエレミヤ

Pinのすべてのインスタンスにはmainその後にスペースがあります。そのため、スペースをセミコロンに置き換えてから削除することにより、文字を保存できます#define。次に、#define他のsの中でs を使用できる場合、同様に、N(x)asの(92==P代わりに書き換えることにより、さらに節約できます。o[i]==92O
algorithmshark 14

@algorithmsharkあなたは明らかに私よりはるかに優れています。助けてくれてありがとう。
ジェリージェレミア14

これは約4年前のものですが、それに応じて書き換えN(x)P;else if(n<x)(P==92?呼び出しを変更するとN、数バイト節約できます。
ザカリー

2

Python 2(236)、Python 3(198?)

from __future__ import print_function
def d(i):
 t=0;p=['']*3+[1]
 while i:
  if'/'==i[0]:t+=1
  else:
   if'\\'==i[0]:i=i[1:]
   p[t]+=i[0]
  i=i[1:]
  print(end=p[0]);p[0]=''
  if t>2:
   while p[1]in i:i=i.replace(*p[1:])
   d(i);i=0

と呼ばれる d(r"""/foo/Hello, world!//B\/\\R/foo/B/\R""")ます。三重引用符は、///プログラムに改行が含まれている場合にのみ必要です。それ以外の場合は、単純な引用符で構いません。

編集:このインタープリターは、期待どおりに内容を印刷するようになりました(以前は最後にのみ印刷されていました、コメントを参照)。Python 3の場合、最初の行を削除します(ただし、以前のインストールにはPython 3がないため、他に変更がないことを確認できません)。


インタープリターは、終了が問題になるまで何も出力しません。///で無限ループを作成することは可能です。そのため、インタプリタは終了しないがまだ印刷しているプログラムでは失敗します。
誇りに思ってhaskeller 14

@proudhaskeller修正済み。
ブルーノルフロック14

実際、これは修正されておらず、何も出力しません/a/ab/bbaa/abb
ベータ崩壊14

/a/ab/bbaa/abb最初の置換がa=> であるため、@ BetaDecay は何も出力せずに無限ループに陥りますaba/ab/bbaa/abb宣伝どおり正しい動作をします。
algorithmshark 14

@BetaDecay:algorithmsharkによって提案された変更-uに加えて、出力バッファを強制的にバッファ解除するコマンドラインオプションを含める必要がある場合があります。
ブルーノルフロック14

2

コブラ-226

sig Z as String
def f(l='')
    m=Z(do=[l[:1],l=l[1:]][0])
    n as Z=do
        if'/'<>(a=m())>'',return if(a=='\\',m(),a)+n()
        else,return''
    print n()stop
    p,s=n(),n()
    if''<l
        while p in l,l=l[:l.indexOf(p)+1]+s+l[p.length:]
        .f(l)


1

Python 2/3(211バイト)

Bruno Le Flochの回答に基づいた次のコードは、Python 2およびPython 3と互換性があります。

さらに、再帰的ではなく反復的であるため、Pythonの最大再帰深度に達するリスクはありません。

def S(c):
 while c:
  B=["","",1]
  for m in 0,1,2:
   while c:
    if"/"==c[0]:c=c[1:];break
    if"\\"==c[0]:c=c[1:]
    if m:B[m-1]+=c[0]
    else:yield c[0]
    c=c[1:]
  while c and B[0]in c:c=c.replace(*B)

こんにちは、PPCGへようこそ。あなたはゴルフができin(0,1,2)in 0,1,2[""]*2+[1]には["","",1]、その結果、211バイト
ジョナサンフレッチ

参照された回答にリンクし、「バイト」という単語を追加しました。編集内容に同意できない場合は、お気軽にロールバックしてください。
ジョナサンフレッチ

ジョナサンに感謝します、あなたの提案は大歓迎です!
カルロスルナ

0

BaCon391 387 395バイト

このページの貢献から、Pythonプログラムのみが機能するようになりました。他は///サンプルで動作するか、まったく動作しません。そのため、BASICの実装であるバージョンを追加することにしました。

BASICは長い単語をステートメントとして使用するため、CodeGolfコンテストでBASICと競争することは容易ではありません。BASICで一般的に見られる略語は「?」のみです。印、PRINTを意味します。

そのため、以下のプログラムは決して勝てないかもしれませんが、少なくともこのCodegolfページとEsolangs Wikiのすべてのデモコードで動作します。「99本のビール」のすべてのバージョンを含む。

p$=""
r$=""
INPUT i$
WHILE LEN(i$)
t$=LEFT$(i$,1)
i$=MID$(i$,2)
IF NOT(e) THEN
IF t$="\\" THEN
e=1
CONTINUE
ELIF t$="/" THEN
o=IIF(o<2,o+1,0)
IF o>0 THEN CONTINUE
FI
FI
IF o=1 THEN
p$=p$&t$
ELIF o=2 THEN
r$=r$&t$
ELIF o=0 THEN
IF LEN(p$) THEN i$=REPLACE$(i$,p$,r$)
IF NOT(INSTR(t$&i$,"/")) THEN
?t$;
BREAK
ELSE
?LEFT$(i$,INSTR(i$,"/")-1);
i$=MID$(i$,INSTR(i$,"/"))
FI
p$=""
r$=""
FI
e=0
WEND
?i$

ユーザーから入力を取得するINPUTステートメントを追加しました。
ピーター
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.