Рекурсивна підстановка рядків


25

Завдання

Напишіть програму або функцію, яка з трьох рядків A, B, Cстворює вихідний рядок, де кожен екземпляр Bв Aрекурсивно заміщений C. Рекурсивно заміщення означає повторення заміни, коли на кожному кроці всі неперекриваються екземпляри Bв A(вибрані жадібно зліва направо) замінюються на, Cпоки Bбільше не містяться в A.

Введення-виведення

  • Ви можете використовувати будь-який із методів за замовчуванням для вводу / виводу .
  • Рядки містять лише друковані символи ASCII (і можуть містити будь-який з них).
  • Bніколи не буде порожнім рядком, хоча Aі Cможе бути.
  • Рядки слід вважати простим текстом, ви не можете, наприклад, трактувати Bяк шаблон Regex.
  • Деякі комбінації входів ніколи не припиняться. У цих випадках ваша програма може робити все, що завгодно.

Тестові справи

Вони у форматі: 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
Ще один тестовий випадок:((())())())/()/
Conor O'Brien

@ ConorO'Brien додав
Лев

1
Спочатку мені не вдалося зробити це чутливим до регістру. downpercase is down
Інженер Тост

Відповіді:


7

05AB1E , 2 байти

`:

Спробуйте в Інтернеті!

Пояснення

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

Це може бути :за 1 байт , якщо ми не маємо справу з порожніми рядками.


3
Якщо я правильно це розумію, ваше 4-байтне рішення є дійсним. "Деякі комбінації входів ніколи не припиняються. Ваша програма може робити все, що завгодно."
Лев

@Leo. Право ти є. Я
скупився

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 байти за допомогою currying (Спасибі @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)
Ніл


@MetoniemSome combinations of inputs will never terminate. Your program can do anything in those cases.
zeppelin

@zeppelin О, бачу.
Metoniem

5

Сітківка , 27 байт

Кількість байтів передбачає кодування ISO 8859-1.

+`(.+)(?=.*¶\1¶(.*))
$2
G1`

Введення має бути розділене між каналами.

Спробуйте в Інтернеті! (Для зручності використовується формат введення тестового набору, де кожен рядок є косою тестовою коробкою.)


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 і фігурних дужок, використовуючи наступне:

  • Присвоєння в дужках повертає присвоєне значення
  • Ліва сторона перевірки рівності буде оцінена перед призначенням правої сторони, що дозволяє нам порівнювати до / після вбудованого рядка та все ще отримувати доступ до результату

Це дозволяє нам зберегти це до однієї заяви.

EDIT: Повернувся до опущення типу функції r, оскільки це видається прийнятним. При оголошенні типу з використанням масивів це 68 символів. Без нього це 44 символи.


Якщо функція буде працювати лише у випадку, якщо вона задається певним іменем, вам потрібно буде витратити байти, щоб надати функції саме таку назву. Для мене не відразу очевидно, чи це 2 байти для r=або багато іншого для декларації (почасти тому, що я не знаю повністю правил, частково тому, що я не знаю C # досить добре, щоб застосувати їх).

Так, я просто це виправляв після того, як прочитав чужий коментар про інший запис. І це набагато більше, оскільки типи повинні бути всі вказані. Я перейшов на використання масиву, щоб заощадити на цьому, і зберегти байти на рекурсивному виклику.
Даніель

Що ви маєте на увазі, якщо не виходить правильний вихід ? Я не думаю, що вам потрібно вводити дані, адже деякі інші відповіді цього не роблять. Я пропустив коментар, сказавши, що мені потрібно вивести вхід?
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 є вбудована рекурсивна заміна, але він бачить перший ввід як регулярний вираз. Якби вхідні дані гарантували лише алфавітно-цифрові символи, це трибайтове рішення спрацювало б:

eVW

Якщо вхід було дозволено містити будь-який символ , за винятком ^, \або ], це 12-байтовое рішення буде дійсним замість:

eV®"[{Z}]"ÃW

2

C #, 33 49 байт

Напевно, один з найменших фрагментів, написаний на C # ... А оскільки Replaceє рідним для stringstruct, немає необхідності в usings ( принаймні, не у вбудованій функції 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 # I upvote
Нельц

@NelsonCasanova Звучить, як я.
Metoniem

Чи Replaceвиконує рекурсивну заміну?
Laikoni

@Laikoni немає. Наприклад, "((())())())".Replace("()", "")повертає (())).
аумман

Тоді це рішення не діє за правилами виклику. Ви повинні видалити його, щоб запобігти знищенню, а потім виправити своє рішення, щоб обробити рекурсивну заміну і, нарешті, відновити його.
Лайконі

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

Математика, 35 32 байт

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

Аргументи наведені як послідовність. Ніколи не припиняється в протягом , growнаприклад, повертається loopдо loopприкладу. На три байти від пропозиції Мартіна.


FixedPointЯк правило, занадто довгий і може бути емульований за допомогою //.:#//.x_:>StringReplace[x,#2->#3]&
Мартін Ендер

Дякую @MartinEnder Це хороший спосіб приступити ReplaceRepeatedдо роботи для струнних!
Сіммонс

btw, це буде лише цикл $RecursionLimitразів, що 2^16за замовчуванням, не те, що це вплине на вашу відповідь
ngenisis

@ngenesis Я не впевнений, що ReplaceRepeatedце контролюється $RecursionLimit- я просто перевірив це, встановивши ліміт до 20, і програма все ще радісно переймається разом для введення без закінчення ..
Сіммонс,

Оскільки ReplaceRepeatedіснує окремий варіант (який неможливо використовувати із //.синтаксисом) MaxIterations. Що за замовчуванням до 2 ^ 16. (cc @ngenisis)
Мартін Ендер

1

Рубін, 29 байт

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

Враховуючи 3 аргументи, застосуйте заміну до першого, поки не буде чим замінити більше.

Пояснення

  • 1перед тим whileпросто ноп
  • gsub!повертає рядок або nilякщо не відбулася заміна


1

/// , 3 байти

///

Поставте рядок B після першого косого кута, C після другого та A в кінці, тобто:

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

Спробуйте в Інтернеті!


Я не думаю, що це прийнятний спосіб приймати матеріали
Лев

Наскільки мені відомо, ///не приймає жодного іншого вкладу.
steenbergh

2
Ну, я думаю, було б цікаво обговорити, чи це прийнятно чи ні, то :) Так чи інакше, я помітив ще одну проблему з вашим поданням: вона не спрацьовує, якщо a /присутній у будь-якому з рядків введення
Лев

1

JavaScript (Firefox 48 або новіші версії), 43 байти

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

Приймає аргументи, викладені у зворотному порядку. Firefox використовував нестандартний третій параметр, для replaceякого вказані прапори regexp. Цей параметр було видалено у 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

Один з рідкісних випадків, коли виконання функції - насправді SHORTER в SmileBASIC.


0

Javascript 130 байт

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

Javascript замінить усіх одночасно, якщо ви надасте йому регулярний вираз. Для того, щоб цей регулярний вигляд працював для всіх значень, всі символи, які використовуються для регулярного вираження, потрібно замінити на уникнуту версію. Нарешті, заміна оцінюється, щоб замінити всі екземпляри B в A на 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)але не працює з якихось причин.


Чи заміняє суб всі або лише перший?
fəˈnɛtɪk

@LliwTelracs, тому що вони є рядками .sub замінить усіх
Downgoat

Це, здається, не працює? Спробуйте в Інтернеті!
Conor O'Brien

@ ConorO'Brien дурні помилкові помилки сторони
терміналу

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помилкою, коли Bпорожній або він подається з подібними даними A/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

Невідомі кодові коди з коментарями:

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.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.