再帰的な文字列置換


25

タスク

3つの文字列を指定してA, B, CBinの各インスタンスがでA再帰的に置換された出力文字列を生成するプログラムまたは関数を記述しCます。再帰的に置換とは、各ステップで重複しないBinのすべてのインスタンスA(左から右に貪欲に選択)がに含まれなくなるCまで置換を繰り返すことを意味BAます。

入出力

  • I / Oにはデフォルトのメソッドを使用できます
  • 文字列には、印刷可能なASCII文字のみが含まれます(また、それらのいずれかが含まれることもあります)。
  • B一方で、空の文字列になることはありませんAし、Cかもしれません。
  • 文字列はプレーンテキストとみなされます。たとえば、扱うことはできません B。、正規表現パターンとして。
  • 入力の一部の組み合わせは終了しません。これらの場合、プログラムは何でもできます。

テストケース

これらは次の形式です。 A/B/C\nOutput

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

Uppercase is up/up/down
Uppercase is down

ababababa/aba/ccc
cccbcccba

delete/e/{empty string}
dlt

{empty string}/no/effect
{empty string}

llllrrrr/lr/rl
rrrrllll

+-+-+-+/+-+/+
+

ababababa/aba/bada
badabbadbada

abaaba/aba/ab
abb

((())())())/()/{empty string}
)

終了しない例:

grow/ow/oow

loop/lo/lo

3
別のテストケース:((())())())/()/
コナーオブライエン

@ ConorO'Brienが追加されました
レオ

1
最初は、大文字と小文字を区別できませんでした。downpercase is down
エンジニアトースト

回答:


7

05AB1E、2バイト

`:

オンラインでお試しください!

説明

`    # split input to stack
 :   # replace (until string doesn't change)

空の文字列を処理する必要がない場合:、これは1バイトになります。


3
正しく理解できれば、4バイトのソリューションは有効です。「入力の組み合わせによっては、終了しないものもあります。その場合、プログラムは何でもできます。」
レオ

@レオ。その通りその通り。私はその部分を
ざっと読みました

1
それで基本的に:、全体の課題を解決するビルトインですか?私はビルトインを禁止すべきだった;)
レオ

@Leo:空の文字列がなければ、単一のビルトインで解決できます。空の文字列との唯一の違いは、3つの入力があることを指定する必要があることです。そうしないと、操作によって暗黙的に推論されます:)
Emigna

このようなことも可能ですか?
アドナン

9

Python 2、43バイト

lambda s,*l:eval('s'+'.replace(*l)'*len(s))

オンラインでお試しください!

フォームの文字列を評価します

s.replace(*l).replace(*l).replace(*l) ...

固定点が存在する場合、それに到達するには、元の文字列の長さに等しい置換を行うだけで十分です。


7

ES6(Javascript)、 47、43バイト

  • カリー化を使用して4バイトを保存(ありがとう@Neil!)

ゴルフ

c=>b=>R=a=>(x=a.split(b).join(c))==a?x:R(x)

それを試してみてください

Q=c=>b=>R=a=>(x=a.split(b).join(c))==a?x:R(x)

function doit() {
  console.log(Q(C.value)(B.value)(A.value));
}
A: <input type="text" value="abaaba" id="A"/> B: <input type="text" value="aba" id="B"/> C: <input type="text" value="ab" id="C"/> <input type="submit" onclick="doit();" value="REPLACE"/>


あなたは逆の順序で引数をカリー化により、4つのバイトを保存することができます:c=>b=>g=a=>a==(a=a.split(b).join(c))?a:g(a)
ニール

おっとっと。i.imgur.com/vPCycwR.png
Metoniem

@メトニエムSome combinations of inputs will never terminate. Your program can do anything in those cases.
ツェッペリン

@zeppelinああ、なるほど。
メトニエム


4

C#、44バイト

短縮版:

r=(a,b,c)=>a==(a=a.Replace(b,c))?a:r(a,b,c);

サンプルプログラム:

using System;

namespace ConsoleApplication1
{
    class Program
    {
    static void Main(string[] args)
        {
            Func<string, string, string, string> r = null;
            r=(a,b,c)=>a==(a=a.Replace(b,c))?a:r(a,b,c);

            Action <string, string, string, string> test =
                (a, b, c, answer) =>
                {
                    var result = r(a, b, c);
                    Console.WriteLine("A: \"{0}\"\r\nB: \"{1}\"\r\nC: \"{2}\"\r\nResult: \"{3}\"\r\n{4}\r\n\r\n",
                        a, b, c, result, result == answer ? "CORRECT" : "INCORRECT"
                        );
                };

            test("Hello, world!", "world!", "PPCG", "Hello, PPCG");
            test("Uppercase is up", "up", "down", "Uppercase is down");
            test("ababababa", "aba", "ccc", "cccbcccba");
            test("delete", "e", "", "dlt");
            test("", "no", "effect", "");
            test("llllrrrr", "lr", "rl", "rrrrllll");
            test("+-+-+-+", "+-+", "+", "+");
            test("ababababa", "aba", "bada", "badabbadbada");
            test("abaaba", "aba", "ab", "abb");
            test("((())())())", "()", "", ")");


            Console.WriteLine("Press any key...");
            Console.ReadKey();
        }
    }
}

説明: 関数は末尾再帰式として記述されており、以下を活用することにより、returnキーワードと中括弧を回避します。

  • 括弧内の割り当ては、割り当てられた値を返します
  • 等価性チェックの左側は右側の割り当ての前に評価され、インラインの前後で比較し、結果にアクセスできます

これにより、単一のステートメントに保つことができます。

編集: 関数rのタイプは省略可能です。配列を使用した型宣言では、68文字です。なしでは、44文字です。


関数が特定の名前を与えられた場合にのみ機能する場合、その名前を関数に与えるためにバイトを費やす必要があります。それr=が宣言のために2バイト以上であるかどうかはすぐにはわかりません(一部はルールを完全に知らないため、一部はそれらを適用するのに十分なC#を知らないためです)。

ええ、私は別のエントリに関する他の人のコメントを読んだ後にそれを修正していました。タイプはすべて指定する必要があるため、さらに多くのことがあります。配列を使用してその上に保存し、再帰呼び出しでバイトを保存することに切り替えました。
ダニエル

正しい出力を生成しないどういう意味ですか?入力を出力する必要はないと思います。実際、他の回答のいくつかはそれを行いません。入力を出力する必要があるというコメントを逃しましたか?
auhmaan

気にしないで、私は問題を見つけました、それは再帰的ではありません。
auhmaan

2

Japt、15バイト

@¥(U=UqV qW}a@U

オンラインでテストしてください!

使い方

@¥(U=UqV qW}a@U  // Implicit: U, V, W = input strings
            a@U  // Return the first non-negative integer mapped by the function X => U
@          }     // that returns truthily when mapped through this function:
     UqV qW      //   Split U at instances of V, and rejoin with W.
  (U=            //   Set U to this new value.
 ¥               //   Return (old U == new U). This stops the loop when U stops changing.
                 // Implicit: output result of last expression

Japtには再帰的置換が組み込まれていますが、最初の入力は正規表現として認識されます。入力に英数字のみが含まれることが保証されている場合、この3バイトのソリューションは機能します。

eVW

入力は任意の文字を含めるさせた場合を除き^\または]、この12バイトのソリューションではなく、有効な次のようになります。

eV®"[{Z}]"ÃW

2

C#、 33 49バイト

おそらく、C#で書かれた最小のスニペットの1つです...そしてReplacestring構造体にネイティブであるため、必要はありません。using sません少なくともVSの組み込み機能、C#Interactiveでは...

また、 B常に値を持っているので、コードは検証を必要としません。


ゴルフ

(a,b,c)=>{while(a!=(a=a.Replace(b,c)));return a;}

非ゴルフ

(a, b, c) => {
    while( a != ( a = a.Replace( b, c ) ) );

    return a;
}

完全なコード

using System;

namespace Namespace {
    class Program {
        static void Main( string[] args ) {
            Func<string, string, string, string> func = (a, b, c) => {
                // Recursively ( now truly recursive ) replaces every 'b' for 'c' on 'a',
                // while saving the value to 'a' and checking against it. Crazy, isn't it?
                while( a != ( a = a.Replace( b, c ) ) );

                return a;
            };

            int index = 1;

            // Cycle through the args, skipping the first ( it's the path to the .exe )

            while( index + 3 < args.Length ) {
                Console.WriteLine( func(
                    args[index++],
                    args[index++],
                    args[index++]) );
            }

            Console.ReadLine();
        }
    }
}

リリース

  • v1.1 - +19 bytes-固定ソリューションは、再帰的なものではありません。
  • v1.0の -  33 bytes-初期ソリューション。

1
私はC#私upvote見る
Nelz

@NelsonCasanova私のように聞こえます。
メトニエム

Replace再帰的な置換を実行しますか?
ライコニ

@ライコニ号 たとえば、を"((())())())".Replace("()", "")返します(()))
auhmaan

その場合、このソリューションはチャレンジのルールでは無効です。ダウン投票を防ぐために削除する必要があります。その後、ソリューションを修正して再帰的な置換を処理し、最終的に削除を取り消します。
ライコニ

1

処理中、75 72バイト

void g(String a,String[]s){for(;a!=(a=a.replace(s[0],s[1])););print(a);}

結果を印刷します。のように呼ぶg("llllrrrr", new String[]{"lr","rl"});

void Q110278(String a, String[]s){             //a is the string to be replaced
                                               //s is the array containing the subsitution

  for(; a!=                                    
            (a = a.replace(s[0], s[1])) ;);

  //for-loop where we continuously perform substitution on a
  //until a is equal to substituted a


  //at the end, print the final version of a
  print(a);
}

1

Mathematica、35 32バイト

#//.x_:>StringReplace[x,#2->#3]&

シーケンスとして与えられる引数。以下のために終了したことがないgrowたとえば、リターンloopのためのloop一例。マーティンの提案のおかげで、3バイトの節約。


FixedPoint長すぎる傾向があり、エミュレートすることができます//.#//.x_:>StringReplace[x,#2->#3]&
マーティンエンダー

@MartinEnderに感謝します。これはReplaceRepeated、文字列を処理する良い方法です!
シモンズ

ちなみに、これはループ$RecursionLimit時間のみ2^16です。これはデフォルトであり、回答に影響するわけではありません
ngenisis

@ngenesisそれReplaceRepeatedが制御されているかどうかはわかりません$RecursionLimit-制限を20に設定してテストしましたが、プログラムはまだ終了しない入力に対して喜んでループします。
Aシモンズ

以下のためにReplaceRepeated(一緒に使用することはできません別のオプションがあります//.構文)と呼ばれますMaxIterationsそのデフォルトは2 ^ 16です。(cc @ngenisis)
マーティンエンダー

1

ルビー、29バイト

->a,b,c{1while a.gsub! b,c;a}

3つの引数が与えられたら、置換するものがなくなるまで最初に置換を適用します。

説明

  • 1whileが単にnopになる前に
  • gsub!文字列を返すnilか、置換が発生しなかった場合


1

///、3バイト

///

文字列Bを最初のスラッシュの後に、Cを2番目の後に、Aを最後に置きます。すなわち:

/<B>/<C>/<A>

オンラインでお試しください!


これは受け入れられる入力方法ではないと思います
レオ

私の知る限り、///他の方法で入力を受け付けません。
steenbergh

2
あれば、それは仕事をしません:まあ、私はそれから、これは許容可能であるかどうかを議論するために興味深いものになるだろう:)とにかくだと思う、私はあなたの提出を持つ別の問題に気づいた/入力文字列のいずれかに存在している
レオ

1

JavaScript(Firefox 48以前)、43バイト

c=>b=>g=a=>a==(a=a.replace(b,c,'g'))?a:g(a)

逆順でカリー化された引数を取ります。Firefoxには、replace正規表現フラグを指定する非標準の3番目のパラメーターがありました。このパラメーターはFirefox 49で削除されました。


0

SmileBASIC、72 68バイト

I=0DEF R A,B,C
I=INSTR(A,B)?A*(I<0)A=SUBST$(A,I,LEN(B),C)R A,B,C
END

関数を作成するまれなケースの1つは、実際にはSmileBASICのSHORTERです。


0

Javascript 130バイト

f=(a,b,c)=>a.indexOf(b)<0?a:f(eval("a.replace(/"+b.replace(/([\/\,\!\\\^\$\{\}\[\]\(\)\.\*\+\?\|\<\>\-\&])/g,"\\$&")+"/g,c)"),b,c)

Javascriptは、正規表現を指定した場合にのみすべてを同時に置き換えます。この正規表現をすべての値に対して機能させるには、正規表現に使用されるすべての文字をエスケープバージョンに置き換える必要があります。最後に、置換が評価されて、AのBのすべてのインスタンスがCに置き換えられ、関数に再び渡されます。



0

チェダー、37バイト

(a,b,c)f->a has b?f(a.sub(b,c),b,c):a

電話でTIOリンクを追加するのは少し難しいです。基本的に、チェックがbがaである間に再帰を使用します。ソリューションは可能性があります(a,b,c)->a.sub(Regex{b,"cr"},c)が、何らかの理由で動作しません。


subはすべてを置き換えますか、それとも最初のものだけを置き換えますか?
fənɛtɪk

@LliwTelracs彼らはすべてを置き換えます.SUB文字列であるので
Downgoat

これはうまくいかないようですか?オンラインでお試しください!
コナーオブライエン

三元の愚かな過ち側がオフになっているConorO'Brienがらくた@
Downgoat

0

Perl 6、40バイト

{$^b;$^c;($^a,{S:g/$b/$c/}...*eq*)[*-1]}

試してください(tio.runが更新された場合)
変更されたバージョンを試してください

拡張:

{
  $^b;           # declare second parameter ( not used here )
  $^c;           # declare third parameter  ( not used here )

  (

    $^a,         # declare first parameter, and use it to seed the sequence

    {S:g/$b/$c/} # replace globally

    ...          # keep doing that

    * eq *       # until there are two that match

  )[*-1]
}


0

PHP、102バイト

list($n,$s,$a,$b)=$argv;$f=str_replace($a,$b,$s);while($s!=$f){$s=$f;$f=str_replace($a,$b,$s);}echo$f;

テストケース(機能的)

ループエラーのあるテストケース


こんにちは!機能を提出する際に通常、あなたはあなたのケースで(:バイトに定義される機能のために必要なすべてのものを追加する必要がありfunction replace(...){...}そうでない場合は、あなたの提出がされたばかりのスニペット、ある、デフォルトでは許可されていない
レオ

@Leoは私の答えを編集した、ことを知らなかった;)
roberto06

0

Java-157バイト

String r(String f){if(f.length()<1)return "";String[]x=f.split("/");if(x[0].contains(x[1]))return r(x[0].replace(x[1],x[2])+'/'+x[1]+'/'+x[2]);return x[0];}

空の入力の場合、空の文字列を返します。

が空の場合、またはこのようなデータが入力されると、StackOverflowExceptionエラーでクラッシュします。BA/A/A

使い方:

r("ABCD/A/F") returns value of r("FBCD/A/F") which returns FBCD
If there is no more characters to be replaced it returns the final output

コメント付きのゴルフのないコードcode:

String r (String f) {
    if(f.length() < 1)
        return ""; // For empty input return empty output
    String[] x = f.split("/"); // Get all 3 parameters
    if (x[0].contains(x[1])) // If input contains replaced value
        return r(x[0].replace(x[1],x[2])+'/'+x[1]+'/'+x[2]); // Return value of r() with one character replaced
    return x[0]; // If nothing to replace return the output(modified input)
}

0

AutoHotkey、87バイト

StringCaseSense,On
Loop{
IfNotInString,1,%2%,Break
StringReplace,1,1,%2%,%3%
}
Send,%1%

%1%%2%、および%3%関数に渡される最初の3つの引数がある
関数は、変数の引数を想定している場合、%sが破棄され
、それなしで、あなたがのようなものを取得し、大文字と小文字の区別の設定を変更する19のバイトがかかりますがdownpercase is down

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