7
\$\begingroup\$

Task

Write a program or function that, given a string and a list of strings, replaces each occurrence of an element of the string list contained in the string with the next element of the string list.

Example

The string is The cat wore a hat on my doormat so I gave it a pat and the list is ["at","or","oo"], we observe that the following bracketed substrings are in the list of strings:

The c[at] w[or]e a h[at] on my d[oo]rm[at] so I gave it a p[at]

We replace each element simultaneously with the element after it. The element after "at" in the list is "or", the element after "or" is "oo", and the element after "oo" is "at". We get

The c[or] w[oo]e a h[or] on my d[at]rm[or] so I gave it a p[or]

so the output is

The cor wooe a hor a on my datrmor so I gave it a por

Note that when we were finding substrings, we selected d[oo]rm[at] instead of do[or]m[at]. This is because the substrings cannot overlap, so when deciding between overlapping substrings we choose the one(s) which come first in the string. When that has ambiguity, we choose the one(s) which come first in the input list.

Input

Input can be taken in any reasonable format. The list can be newline-delimited, space-delimited, or delimited by any reasonable character.

Output

Output the string generated after the replacements

Rules

  • You may assume that the input string and list consist only of printable ASCII (0x20 to 0x7E).
  • You may assume that the strings in the input list do not contain your delimiter.
  • You may assume that the input list has no repeated elements.
  • None of the Standard Loopholes are allowed.
  • Since this is , lowest score in bytes wins.

Testcases

String
List of Strings
Output
-----
"My friend John went to the park."
["j","J"," "]
"Myjfriendj ohnjwentjtojthejpark."
-----
"Monkey Tacos!"
["Monkey","Programming Puzzles"," "," & ","Tacos!","Code Golf", "Puzzles", "Dragons"]
"Programming Puzzles & Code Golf"
-----
"No matches this time :("
["Match","Duel","(No"]
"No matches this time :("
-----
"aaaaa"
["aa","b","a","c"]
"bbc"
-----
"aaaaa"
["b","a","c","aa"]
"ccccc"
-----
"pencil"
["enc","pen","nci","cil"]
"ncienc"
-----
"Seriously, a lowercase rot one?"
["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"]
"Sfsjpvtmz, b mpxfsdbtf spu pof?"
\$\endgroup\$
3
\$\begingroup\$

JavaScript (ES6), 99 bytes

f=(s,a,i=a.findIndex(w=>s.startsWith(w)))=>s?(~i?a[i+1]||a[0]:s[0])+f(s.replace(a[i]||s[0],''),a):s
\$\endgroup\$
  • \$\begingroup\$ Is this not actually 97 bytes? try it online \$\endgroup\$ – Octopus May 26 '17 at 1:57
  • \$\begingroup\$ @Octopus The f= is counted in the bytecount because it is being referenced in the function f(s.replace... \$\endgroup\$ – Kritixi Lithos May 26 '17 at 6:29
2
\$\begingroup\$

Java 8, 227 215 bytes

q->a->{String s=q,t;for(int i=0,j,l=a.length-1;i<s.length();i++)for(j=0;j<=l;j++)if(i==i+s.substring(i).indexOf(a[j])){s=s.substring(0,i)+(t=a[j<l?j+1:0])+s.substring(i+a[j].length());i+=t.length()-1;j=l;}return s;}

Ok, I got to admit: this challenge looks easy on paper, but there are many edge-cases for a verbose programming language like Java.. The first test case was easy, and was responsible for the general approach. The second test case caused a problem where it skipped two characters that both had to be replaced in a row <space>J -> j<space>. And then I had to fix another problem where test case "aaaaa"; ["aa","b","a","c"] resulted in bcb instead of the intended bbc. Oh, and the third test case replaced the Puzzles part twice at one point as well.. But, everything is fixed now, and all test-cases work.

Explanation:

Try it here.

q->a->{String s=q,                        // Method with String & String-array parameters and String return-type
  ,t                                      //  Temp String
  for(                                    //  Loop (1) over the characters of the input String
      int i=0,j,l=a.length-1,t;           //  Some temp integers
                               i<s.length();i++)
    for(j=0;j<=l;j++)                     //   Loop (2) over the String-array
      if(i==i+s.substring(i).indexOf(a[j])){
                                          //    If we've found a match:
        s=                                //     Replace the input-String with:
          s.substring(0,i)                //      The first part of this input-String
          +(t=a[j<l?j+1:0])               //      + the next item in the String-array (and set `t` to it)
          +s.substring(i+a[j].length());  //      + the last part of this input-String
        i+=t.length()-1;                  //     Raise `i` by the length of this replacement item (`t`) - 1
        j=l;//break;                      //     Break loop (2)
      }                                   //    End of if
                                          //   End of loop (2) (implicit / single-line body)
                                          //  End of loop (1) (implicit / single-line body)
  return s;                               //  Return resulting String
}                                         // End of method
\$\endgroup\$
  • 1
    \$\begingroup\$ As always, convert to Java 8 and use an anonymous function with currying to save bytes. Other than than I'm not sure there's much more you can golf, well done. \$\endgroup\$ – TheLethalCoder May 26 '17 at 9:52
  • \$\begingroup\$ @TheLethalCoder Ok, ok. I'll try to use Java 8 some more from now on.. ;) (And thanks.) \$\endgroup\$ – Kevin Cruijssen May 26 '17 at 10:04
  • \$\begingroup\$ Haha! I'll put my bloody 8 away and stop beating you with it then. \$\endgroup\$ – TheLethalCoder May 26 '17 at 10:05
  • 1
    \$\begingroup\$ @TheLethalCoder Hehe. I actually answered something else this morning in just Java 8. Was thinking about switching to Java 8 from now on, but I still prefer to make these challenges in Java 7 locally.. I just have to remember to convert them to Java 8 before I post them here. \$\endgroup\$ – Kevin Cruijssen May 26 '17 at 10:07
2
\$\begingroup\$

Japt, 14 13 bytes

It's early so probably room for improvement.

rVq| @VgVbX Ä

Try it online


Explanation

                  :Implicit input of string U
r                 :Replace in U
 Vq|              :  V joined to a string with "|" (which is RegEx "or")
     @            :  Pass each match X through a function
        VbX       :    Index of X in V
            Ä     :    Add 1
     Vg           :    Get the element at that index in V
\$\endgroup\$
1
\$\begingroup\$

Python 2, 89 bytes

import re
s,a=input()
print re.sub('(%s)'%')|('.join(a),lambda m:a[m.lastindex%len(a)],s)

re.sub can use a replacer function, it just gets a shifted value from the original list.

\$\endgroup\$
1
\$\begingroup\$

APL (Dyalog), 12 bytes

Main answer

Needs escapeing of things that will clash with PCRE, which is acceptable.

{⍺⎕R(1⌽⍺)⊢⍵}

For each non-overlapping, sequential occurrence of each element of the left argument (), Replace (⎕R) the occurrence with the corresponding element of the left argument rotated one step left (1⌽⍺), applied to () the right argument ().


For general interest

A version which needs less escaping

Some arguments will clash with PCRE, so to avoid requiring the input to be pre-escaped, we can enclose each search pattern in \Q and \E:

{('\Q'∘,¨,∘'\E'¨⍺)⎕R(1⌽⍺)⊢⍵}

New here are '\Q' prepended (∘,) to each (¨) and append (,∘) '\E' to each (¨).

A version which needs no escaping

Still, this requires escaping any premature \E and also certain characters in the transformation patterns, so we can preprocess the search and transformation patterns to escape all problematic characters:

{R←⎕R'\\&'⋄('\P{Xan}'R⍺)⎕R(1⌽'\\|%|&'R⍺)⊢⍵}

R←⎕R'\\&' define the monadic operator R by currying the transformation pattern \\& (prefix a backslash to the matched text) as right operand.

 then

'\\|%|&'R⍺ call R, looking for any backslash or percent or ampersand, (i.e. prefix them with a backslash) on the left argument

1⌽ rotate that one step to the left

'\P{Xan}'R⍺ call R, looking for any non-alphanumeric character, (i.e. prefix them with a backslash) on the left argument

()⎕R()⊢⍵Replace text in the right argument – this time with safe search and transformation patterns

\$\endgroup\$
  • \$\begingroup\$ I think requiring certain escaped strings in the input is fine because that is a quirk of how the language deals with input. I don't know APL, so I'm not sure this is exactly how it works. \$\endgroup\$ – fireflame241 May 26 '17 at 14:10
  • \$\begingroup\$ @fireflame241 Thank you, that's what I thought. \$\endgroup\$ – Adám May 26 '17 at 14:33
1
\$\begingroup\$

PHP>=7.1, 79 Bytes

<?[$s,$o]=$_GET;$k=$o;$k[]=array_shift($k);echo strtr($s,array_combine($o,$k));

Online Version

\$\endgroup\$
1
\$\begingroup\$

Ruby, 50 bytes

->a,b{a.gsub(%r[#{b*?|}]){|z|(b*2)[b.index(z)+1]}}

Straight forward as always :)

\$\endgroup\$
0
\$\begingroup\$

C#, 199 bytes

s=>a=>{for(int i=0,j,l=a.Count-1,t;i<s.Length;i++)for(j=0;j<=l;j++)if(i==i+s.Substring(i).IndexOf(a[j])){s=s.Substring(0,i)+a[t=j<l?j+1:0]+s.Substring(i+a[j].Length);i+=a[t].Length-1;j=l;}return s;};

A straight port of @KevinCruijssen's answer so go give him an upvote!

It's unfortunate that string.Split in C# removes the split strings otherwise I'm sure that would have been shorter.

\$\endgroup\$
0
\$\begingroup\$

PHP, 66 bytes

while($t=$argv[++$i+2])$p[$argv[$i+1]]=$t;echo strtr($argv[1],$p);

takes input from command line arguments; assumes that none of the arguments is 0.

Run with php -nr '<code>'.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.