web-dev-qa-db-ja.com

正規表現はプログラミング言語ですか?

学術的な意味で、正規表現はプログラミング言語として認められますか?

私の好奇心の動機は SOの質問 「regexはXを実行できるか?」そして、それらを使用する可能な解決策について、一般的な意味で何が言えるのか不思議に思いました。

私は基本的に「正規表現チューリングは完全ですか」と尋ねています。

28
Aaron Anodide

正規表現は特定の種類の 形式文法 であり、形式言語理論では「正規言語」として知られている文字列やその他のテキスト情報を解析するために使用されます。それらは、そのようなプログラミング言語ではありません。それらは、実装するのが非常に退屈であり、時々不可解に見える正規表現よりもさらに混乱するコーディングの略記です。

プログラミング言語は通常、 Turing Complete の言語として定義されます。そのような言語は 計算可能な関数 を処理できなければなりません。正規表現はこのカテゴリに適合しません。

正規表現のような言語が必要な場合は、Jを試してください。

49
World Engineer

タイプ「is [〜#〜] x [〜#〜] a [〜#〜] y [〜#〜] "の質問に答えることは困難です。討論の参加者は、[〜#〜] x [〜#〜][〜#〜] y [〜#〜]の異なる定義を使用します。一部の定義では答えは「はい」であり、一部の定義では答えは「いいえ」である可能性があります。特に、答えが技術的詳細に依存する場合は、さまざまな定義が異なります。また、このディスカッションには誤った情報が含まれているため、より長い回答をお待ちください。

プログラミング言語」とはどういう意味ですか?

簡単な答えは、「プログラムの作成に使用される言語」かもしれません。もちろん、どのようなプログラムですか? some種類のプログラムを作成するために使用できるが、他の種類のプログラムは使用できない言語についてはどうですか?極端なケースを説明する2つの具体的な例を次に示します。

1)Mと呼ばれる架空の言語は次のように機能します。プログラムに「m」という1文字が含まれている場合、マインスイーパのゲームが作成されます。それ以外はすべて構文エラーです。

直感的に、これはnotが「プログラミング言語」と言うことの意味です。しかし、Mのマーケティング部門は、それが技術的にで定義を満たしていると主張することができます。なぜなら、それはcanがプログラムの作成に使用されるためです。確かに、コンパイラーはいくつかの重要な部分を実行しますが、それはコンパイラーが行うことですよね。 C言語のコンパイラは、いくつかの単純な単語を数十のプロセッサ命令に変換します。 Mコンパイラーはさらに進んで、ジョブをさらに単純化します。

2)有名なTurbo Pascalのオリジナルバージョンをインストールすれば、さまざまな種類のプログラムを書くことができます。ただし、必要なAPIが存在しないため、Webブラウザーで実行するゲームを作成することはできません。

では、Turbo Pascalをプログラミング言語にしているのは正確には何ですか。簡単に言えば、MでよりもPascalでmoreを実行できます。ただし、Webブラウザーで実行されるマインスイーパーゲームを作成するM.NETがあるとします。これで、PascalができることとM.NETができないことがあるようになりましたが、M.NETができることとPascalができないこともあります。 Pascalの利点は重要であり、M.NETの利点は無関係であると考える必要があるのはなぜですか。

答えは、Pascalではalgorithmsのすべての種類を記述できますが、MまたはM.NETではalgorithmsを記述できないためです。確かに、Mはコマンド「m」をコンパイルし、Cはコマンド「strcmp」をコンパイルします。しかし、「strcmp」をより大きなコンテキストに置くことができます。たとえば、2つのファイルを行ごとに比較したり、1,000個の文字列を読み取ってそれらをアルファベット順にソートしたりできます。そして、プログラミング言語の本質を作るのは、与えられたコマンドをany algorithmで使用するまさにこの能力です。

正確にはアルゴリズムとは何ですか?さらに重要なことに、「任意のアルゴリズム」とは何ですか?コンピュータサイエンスでは、単語 Turing-complete を使用します。アイデアは、それぞれがsimulateそれらのすべてを実行できる一連のコンピューター言語があるということです。それらの言語の1つはTuringマシンです。そのため、そのように呼ばれています。 Pascalあり、Cあり、Javaあり、Pythonあり、LISPあり、Smalltalkあり、XSLTさえあります。仮想MとM.NETはnotあります。これについては、まともなコンピュータサイエンスコースを提供しているどの大学でも学ぶことができますが、チューリング完全言語でできることは、anything =必要な最低限のAPIを提供すれば、別のチューリング完全言語で実行できること(PascalにWebブラウザーAPIを提供すれば、Webブラウザーであらゆる種類のゲームを作成できます。WebブラウザーAPIを提供するとMに対しては、まだマインスイーパを作成することしかできません。)比喩的に言えば、プログラミング言語からすべてのAPIを削除した場合、重要なものは残っていることです。

正規表現」とはどういう意味ですか?

プログラミング言語が異なれば、実装方法も少し異なります。しかし、元々の考えは、正規表現はいわゆる 通常の言語 を表すというものでした。ここではプログラミング言語についてではなく、(疑似)人間の言語について話しています。 「ba」、「baba」、「bababa」などの単語だけで構成される言語を話すエキゾチックな部族がいると想像してください。この言語は、「1つの音節 'ba'が1回以上繰り返される」、または正規表現を使用して「(ba)+」と口頭で説明できます。

正規表現は、「なし」、「この文字」、「これ、その後に続く」、「これまたはそれ」、「これ、1回以上繰り返される」、「これではない」を表現することになっています。 -それがmathematicalの定義です。それ以外は、以前のコンポーネントから構築された便利なショートカットです。たとえば、「これ、2、3回繰り返される」は「これ、これがこれに続き、(これまたは何もない)」と翻訳できますが、「baba」よりも「ba {2,3}」と書く方が便利です。 (ba)?」.

実際には、「正規表現」の一般的な実装はmoreを実装しています。たとえば、数学的な定義を使用すると、「aba」、「aabaa」、「aaabaaa」などの言語-任意の数の「a」、その後に「b」、その後に続く同じ "a"の数-is not通常の言語。しかし、今日使用されている多くの「正規表現」は、「以前に見つけたのと同じもの」という追加の概念を使用して、「(a +)b\1」と書かれてそれを検出できました。この追加の概念を使用して、たとえばprime文字数で構成される単語を検出するなど、いくつかのクールなことができます。それでも、私たちはできませんany algorithm ...理由の説明は、 形式言語 のテキストをご覧ください。

それで、元のトピックに戻ります:正規表現(Chomsky階層の正規言語を記述する式、または前者と\ 1演算のいずれかとして定義)は、プログラミング言語(Turing-completeとして定義)ですか?答えはnoです。いいえ、正規表現を使用してany algorithmを実装することはできません。any algorithmを実装する機能は、コンピューターサイエンスを研究している人々がプログラミング言語の本質として一般的に理解しているものです。

もちろん、誰でも別の定義を主張することで答えを変えることができます。最初に書いたように、技術的な詳細はここで重要です。それらを間違えると、間違った答えが返ってきます。

そして、もしあなたがnot技術的な詳細に興味があるなら、答えは次のようになります:正規表現を使って(そして他に何も)プログラムを作ることはできますか?いいえ。なぜそれをプログラミング言語と呼ぶのでしょうか。 (ただし、このような回答はここでダウンロードおよび削除されたため、この長いバージョンを作成しました。)

編集:また、誰もがいくつかの追加された新機能を備えた「正規表現」の独自の新しいバリアントを実装するライブラリを作成できます。いつか、新機能mayでシステム全体がチューリング完全になるのに十分です。簡単な例は、新しい構文を使用してチューリング完全言語を埋め込むことです。しかし、それはあまり明確に発生しない場合もあります。多分それはすでに起こった。

14
Viliam Búr

以前の回答で説明したように、正規表現の1つの検索/置換はチューリング完全プログラミング言語ではありませんが、正規表現で置換するアクションを繰り返し使用できる場合は、正規表現を使用して任意のチューリングマシンをエンコードできます。

繰り返し検索/正規表現で置換することは、チューリング完全プログラミング言語です

結果として、同じ検索を使用して計算可能な関数を計算し、JavaScript正規表現を何度も置き換えることができます。

チューリングの完全性を証明するには、正規表現の検索/置換でチューリングマシンをエンコードするだけで十分です。エディターの状態は次のとおりであると想定します。

0000#12345:01-5:0#0000000

リーダーが付いているシンボルのテープとして読むことができます:

[left symbols]#[set of states]:[set of symbols]-[current state]:[current symbol]#[right symbols]

状態5で0を読み取り、1を書き込み、その状態を3に変更して左に移動するルールの場合、次の表記法を使用してそれを抽象化します。

5:0 => 1, 3:[left]

以前の表記を検索正規表現にエンコードします。

(\d)#(1)(2)(3)(4)(5):(0)(1)-5:0#

とその置換式(JavaScriptのような)

#12345:01-$4:$1#$8

では、多くのルールをどのようにエンコードするのでしょうか。正規表現検索にはor演算子|との連結を使用し、結果を置換で組み合わせて、グループ番号をオフセットで数値化します。たとえば、4つのルールのセットを考えてみましょう。

5:0 => 1, 3:left
3:0 => 1, 5:right
5:1 => 1, 5:right
3:1 => 1: 3:stop

それらを検索でエンコードし、式を置き換えます。

Search:
(\d)#(1)(2)(3)(4)(5):(0)(1)-5:0#|#(1)(2)(3)(4)(5):(0)(1)-3:0#(\d)|#(1)(2)(3)(4)(5):(0)(1)-5:1#(\d)|#(1)(2)(3)(4)(5):(0)(1)-3:1#

Replace by:
$15$23#12345:01-$4$13$21$27:$1$16$24$31#$8

お気に入りのJavaScriptエンジンで試してください。

function turingstep(s) {
  return s.replace(/(\d)#(1)(2)(3)(4)(5):(0)(1)-5:0#|#(1)(2)(3)(4)(5):(0)(1)-3:0#(\d)|#(1)(2)(3)(4)(5):(0)(1)-5:1#(\d)|#(1)(2)(3)(4)(5):(0)(1)-3:1#/g,"$15$23#12345:01-$4$13$21$27:$1$16$24$31#$8");
}

var tape = "0000#12345:01-5:0#0000000"
for(var i = 0; i < 6; i++) {
  console.log(tape)
  tape = turingstep(tape)
}
1
Mikaël Mayer

.Netでは、正規表現は、代替とルックアラウンドのさまざまな組み合わせを使用して、複数の形式の条件を処理できるだけでなく、独自のスタックを操作することもできます。

(?xm)
    (?>
        <(?<Tagname>table)[^>]*>
    )
(?(Tagname)
    (
        </(?(?!\k'Tagname')(?<-Tagname>))*\k'Tagname'>(?<-Tagname>)
    |
        (?>
            <(?<Tagname>[a-z][^\s>]*)[^>]*>
        )
    |
        [^<]+
    )+?
    (?(Tagname)(?!))
)

これは、たとえば、HTMLテーブルを取得するために私が書いた小さなスニペットです。他の正規表現エンジンとは異なり、これはキャプチャコレクションのスタック(プッシュ、ピーク、ポップ)を制御し、ネストされたオブジェクトを処理できます。私はもっ​​と複雑なものを持っていますが、それはちょっと独自のものです。

この例では、Regexはプログラミング言語のすべての基本要件を備えていると見なすことができると思います。変数、インラインメモリ、条件、入力と出力があり、複数の正規表現コンパイルエンジン(この場合は.Net)の1つを使用してコンパイルします。

正規表現でHTMLを解析する(絶対に使わない)への使いすぎへの対応として、私は先に進み、投稿できる事前に入力された応答を投稿しました。 HTMLの解析

Anoterの例(単なるデモ)は次のとおりです。

Function Regex("<(td>)((?:[^<]*(?(?!</\1)<))*)</\1")
    Group(0) = "<"
    Group(1) = "td>"
    Group(0) += Group(1)
    Group(2) = LoopMethod()
    Group(0) += Group(2)
    Group(0) += "</" & Group(1)
    Return Group()
End Function

Function LoopMethod()
    retGroup = ""
    Do
        tmpGroup = Everything that is NOT an Opening HTML Delimeter
        If the Text following tmpGroup Does NOT Equal "</" & Group(1) Then
            tmpGroup += "<"
            retGroup += tmpGroup
        Else
            Exit Do
        End If
    Loop
    Return retGroup
End Function

ここでも、HTMLオウムの場合: HTMLの解析

これは、ループと条件文(アルゴリズム?)を実行する単純な正規表現を示しています。不足しているのは、実際の数学的計算だけです。これは、通常の "(。*?)"メソッドよりも効率的にTDセルをプルするだけの、より詳細な正規表現です。

しかし、Regexの熱狂者であり、自称マスターであっても、Regexがプログラミング言語であることを他の人に教えようとはしません。私自身に対する私自身の議論は、それは独立することはできず、別のプログラミング言語エンジンによってサポートされている間、それ自身のエンジンを通して実行されなければならないということです。

0
Suamere