17
\$\begingroup\$

The idea is simple. You've to create a "visualised" letter-replacement, by providing 3 strings (input can be comma separated, separate inputs, or as an array). The first segment is the word you want to correct, and the second segment is the letters you want to replace, and the third segment is the replacement for the letters in segment 2.

For example:

|    | Input                       | Starting Word | Output      |
|----|-----------------------------|---------------|-------------|
| #1 | Hello world -wo -ld +Ea +th | Hello world   | Hello Earth |
| #2 | Hello World -wo -ld +Ea +th | Hello World   | Hello Worth |
| #3 | Hello -llo +y               | Hello         | Hey         |
| #4 | Red -R -d +Gr +en           | Red           | Green       |
| #5 | mississippi -is -i +lz +p   | mississippi   | mlzslzspppp |
| #6 | Football -o -a +a +i        | Football      | Fiitbill    |
| #7 | mississippi -is -i +iz +p   | mississippi   | mpzspzspppp |

Explanation

The replacements are to be done step-by-step with their respective pair. Here's an illustration with an input of mississippi -is -i +iz +p to give the output mpzspzsppp (see example #7 above)

| Step  | Input                         | Output        |
|------ |---------------------------    |-------------  |
| #1    | mississippi -is -i +iz +p     |               |
| #2    | mississippi -is +iz           | mizsizsippi   |
| #3    | mizsizsippi -i +p             | mpzspzspppp   |

Rules

  • Inputs are always in this order <starting_string> <list_of_letters_to_replace> <replacement_letters>.
  • Letters to replace and replacement groups will never be mixed (ie: there will never be -a +i -e +o).
  • Letters to replace are always prefixed with - and replacement letters are always prefixed with +. (The prefix is mandatory)
  • There may be more than one set of letters to replace, so you'd need to look at the prefix.
  • Assume the amount of letter groups to replace and the amount of replacement letter groups are always equal (ie: there will never be -a -e +i)
  • Replacements are case-sensitive (see example #1 and #2).
  • Replacements are done in the order they were given in the input.
  • Letter replacements can be replaced with other replacements. See example #6.
  • The first segment (starting word) will never include - or + characters.
  • This is code-golf so shortest bytes win.

Leaderboards

Here is a Stack Snippet to generate both a regular leaderboard and an overview of winners by language.

To make sure that your answer shows up, please start your answer with a headline, using the following Markdown template:

# Language Name, N bytes

where N is the size of your submission. If you improve your score, you can keep old scores in the headline, by striking them through. For instance:

# Ruby, <s>104</s> <s>101</s> 96 bytes

If there you want to include multiple numbers in your header (e.g. because your score is the sum of two files or you want to list interpreter flag penalties separately), make sure that the actual score is the last number in the header:

# Perl, 43 + 2 (-p flag) = 45 bytes

You can also make the language name a link which will then show up in the leaderboard snippet:

# [><>](http://esolangs.org/wiki/Fish), 121 bytes

var QUESTION_ID=96473,OVERRIDE_USER=38505;function answersUrl(e){return"http://api.stackexchange.com/2.2/questions/"+QUESTION_ID+"/answers?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+ANSWER_FILTER}function commentUrl(e,s){return"http://api.stackexchange.com/2.2/answers/"+s.join(";")+"/comments?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+COMMENT_FILTER}function getAnswers(){jQuery.ajax({url:answersUrl(answer_page++),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){answers.push.apply(answers,e.items),answers_hash=[],answer_ids=[],e.items.forEach(function(e){e.comments=[];var s=+e.share_link.match(/\d+/);answer_ids.push(s),answers_hash[s]=e}),e.has_more||(more_answers=!1),comment_page=1,getComments()}})}function getComments(){jQuery.ajax({url:commentUrl(comment_page++,answer_ids),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){e.items.forEach(function(e){e.owner.user_id===OVERRIDE_USER&&answers_hash[e.post_id].comments.push(e)}),e.has_more?getComments():more_answers?getAnswers():process()}})}function getAuthorName(e){return e.owner.display_name}function process(){var e=[];answers.forEach(function(s){var r=s.body;s.comments.forEach(function(e){OVERRIDE_REG.test(e.body)&&(r="<h1>"+e.body.replace(OVERRIDE_REG,"")+"</h1>")});var a=r.match(SCORE_REG);a&&e.push({user:getAuthorName(s),size:+a[2],language:a[1],link:s.share_link})}),e.sort(function(e,s){var r=e.size,a=s.size;return r-a});var s={},r=1,a=null,n=1;e.forEach(function(e){e.size!=a&&(n=r),a=e.size,++r;var t=jQuery("#answer-template").html();t=t.replace("{{PLACE}}",n+".").replace("{{NAME}}",e.user).replace("{{LANGUAGE}}",e.language).replace("{{SIZE}}",e.size).replace("{{LINK}}",e.link),t=jQuery(t),jQuery("#answers").append(t);var o=e.language;/<a/.test(o)&&(o=jQuery(o).text()),s[o]=s[o]||{lang:e.language,user:e.user,size:e.size,link:e.link}});var t=[];for(var o in s)s.hasOwnProperty(o)&&t.push(s[o]);t.sort(function(e,s){return e.lang>s.lang?1:e.lang<s.lang?-1:0});for(var c=0;c<t.length;++c){var i=jQuery("#language-template").html(),o=t[c];i=i.replace("{{LANGUAGE}}",o.lang).replace("{{NAME}}",o.user).replace("{{SIZE}}",o.size).replace("{{LINK}}",o.link),i=jQuery(i),jQuery("#languages").append(i)}}var ANSWER_FILTER="!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe",COMMENT_FILTER="!)Q2B_A2kjfAiU78X(md6BoYk",answers=[],answers_hash,answer_ids,answer_page=1,more_answers=!0,comment_page;getAnswers();var SCORE_REG=/<h\d>\s*([^\n,]*[^\s,]),.*?(\d+)(?=[^\n\d<>]*(?:<(?:s>[^\n<>]*<\/s>|[^\n<>]+>)[^\n\d<>]*)*<\/h\d>)/,OVERRIDE_REG=/^Override\s*header:\s*/i;
body{text-align:left!important}#answer-list,#language-list{padding:10px;width:290px;float:left}table thead{font-weight:700}table td{padding:5px}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b"> <div id="answer-list"> <h2>Leaderboard</h2> <table class="answer-list"> <thead> <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr></thead> <tbody id="answers"> </tbody> </table> </div><div id="language-list"> <h2>Winners by Language</h2> <table class="language-list"> <thead> <tr><td>Language</td><td>User</td><td>Score</td></tr></thead> <tbody id="languages"> </tbody> </table> </div><table style="display: none"> <tbody id="answer-template"> <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table> <table style="display: none"> <tbody id="language-template"> <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table>

\$\endgroup\$
10
  • 1
    \$\begingroup\$ Given rules 2 and 5, you really don't need to look at the prefix. With n inputs, input 0 is the base string, inputs 1 to int(n/2) are letter to replace (with prefix -) and input int(n/2)+1 to n-1 are replacement (with prefix +) \$\endgroup\$
    – edc65
    Oct 17, 2016 at 8:51
  • \$\begingroup\$ @edc65 100% true, although the challenge was designed to have the prefix (and I could make up some weird explanation that I'm an alien who cannot process letter replacements without their prefix) but in reality, it's just another barrier to stop this being too trivial - though looking at the current answers (all are great by the way) it wasn't a complex barrier. Also fun fact, the idea behind this challenge was spawned from my friend in a Skype chat. He'd mis-spell a word (gello), and then send me the letter replacements (-g +h) because he wanted to be annoying instead of sending hello*. \$\endgroup\$
    – ʰᵈˑ
    Oct 17, 2016 at 8:57
  • 1
    \$\begingroup\$ Inputs are always in this order Why so restrictive? \$\endgroup\$
    – Luis Mendo
    Oct 17, 2016 at 9:16
  • \$\begingroup\$ @LuisMendo I guess it doesn't really matter - but it's the way my friend and I formatted it, but since answers have been posted to this requirement, I cannot really make a rule change. It wasn't questioned on the sandbox, so I didn't think of it as a negative. \$\endgroup\$
    – ʰᵈˑ
    Oct 17, 2016 at 9:23
  • 1
    \$\begingroup\$ @udioica is perfecly right and it in fact support the "Replacements are case-sensitive" rule. Run the snippet in the JavaScript answer to see it implemented. (#1 world` vs #2 World) \$\endgroup\$
    – edc65
    Oct 17, 2016 at 12:31

15 Answers 15

6
\$\begingroup\$

05AB1E, 15 17 bytes

IIð¡€áIð¡€á‚øvy`:

Try it online!

Explanation

I                   # read starting string
 I                  # read letters to be replaced
  ð¡                # split on space
    ۇ              # and remove "-"
      I             # read replacement letters
       ð¡           # split on space
         ۇ         # and remove "+"
           ‚ø       # zip to produce pairs of [letters to replace, replacement letters]
             vy`:   # for each pair, replace in starting string

Or with a less strict input format

vy`:

Try it online

\$\endgroup\$
6
\$\begingroup\$

JavaScript (ES6), 85 83 bytes

f=(s,n=1,l=s.split(/ \W/))=>(r=l[n+l.length/2|0])?f(s.split(l[n]).join(r),n+1):l[0]

Test cases

f=(s,n=1,l=s.split(/ \W/))=>(r=l[n+l.length/2|0])?f(s.split(l[n]).join(r),n+1):l[0]

console.log(f("Hello world -wo -ld +Ea +th"));
console.log(f("Hello World -wo -ld +Ea +th"));
console.log(f("Hello -llo +y"));
console.log(f("Red -R -d +Gr +en"));
console.log(f("mississippi -is -i +lz +p"));
console.log(f("Football -o -a +a +i"));
console.log(f("mississippi -is -i +iz +p"));

\$\endgroup\$
5
\$\begingroup\$

Pyke, 13 11 bytes

z[zdcmt)[.:

Try it here!

z           - input()
 [zdcmt)    - def func():
  zdc       -  input().split(" ")
     mt     -  map(>[1:], ^)
            - func()
        [   - func()
         .: - translate()

Or 2 bytes if in a different input format:

.:

Try it here!

\$\endgroup\$
4
  • \$\begingroup\$ At work catbus.co.uk is blocked. Are you able to link an alternative test suite please? \$\endgroup\$
    – ʰᵈˑ
    Oct 17, 2016 at 9:24
  • 2
    \$\begingroup\$ @ʰᵈˑ I don't believe conforming to your (arbitrary) work firewall settings is reasonable. \$\endgroup\$
    – orlp
    Oct 17, 2016 at 10:12
  • 1
    \$\begingroup\$ @orlp - I agree, it's shit. But I don't set the firewall settings. I just wanted to test it out \$\endgroup\$
    – ʰᵈˑ
    Oct 17, 2016 at 10:25
  • 2
    \$\begingroup\$ @hd you can download Pyke at github.com/muddyfish/pyke \$\endgroup\$
    – Blue
    Oct 17, 2016 at 11:18
4
\$\begingroup\$

Perl, 58 bytes

57 bytes code + 1 for -p.

Requires first item on one line, then the replacements on the next. Big thanks to @Dada who came up with a different approach to help reduce by 4 bytes!

$a=<>;1while$a=~s%-(\S*)(.*?)\+(\S*)%"s/$1/$3/g;q{$2}"%ee

Usage

perl -pe '$a=<>;1while$a=~s%-(\S*)(.*?)\+(\S*)%"s/$1/$3/g;q{$2}"%ee' <<< 'Football
-o -a +a +i'
Fiitbill
perl -pe '$a=<>;1while$a=~s%-(\S*)(.*?)\+(\S*)%"s/$1/$3/g;q{$2}"%ee' <<< 'mississippi
-is -i +iz +p'
mpzspzspppp
perl -pe '$a=<>;1while$a=~s%-(\S*)(.*?)\+(\S*)%"s/$1/$3/g;q{$2}"%ee' <<< 'mississippi
-ippi -i -mess +ee +e +tenn'
tennessee
\$\endgroup\$
5
  • \$\begingroup\$ 4 bytes longer, there is perl -pE 's/(.*?) -(\S*)(.*?)\+(\S*)/"(\$1=~s%$2%$4%gr).\"$3\""/ee&&redo'. I can't manage to get it any shorter, but maybe you can :) \$\endgroup\$
    – Dada
    Oct 17, 2016 at 15:51
  • 1
    \$\begingroup\$ Gotcha! 58 bytes : perl -pE '$a=<>;1while$a=~s%-(\S*)(.*?)\+(\S*)%"s/$1/$3/g;q{$2}"%ee'. (takes the string on one line, and the "flags" on the next line) \$\endgroup\$
    – Dada
    Oct 17, 2016 at 17:55
  • 1
    \$\begingroup\$ Awesome! I'm not at a computer but I'll update that tomorrow! Thanks! \$\endgroup\$ Oct 17, 2016 at 20:47
  • \$\begingroup\$ Are you sure about removing the q{} surrounding $2 ? Wouldn't this fail when there are 3 - and 3 + switches? (I can't test it now, so maybe you were right so remove it ;) ) \$\endgroup\$
    – Dada
    Oct 18, 2016 at 11:13
  • \$\begingroup\$ @Dada ahhh, I did wonder why you'd added it, I tested all the cases in the test suite, but didn't think about a 3 for 3 replacement... \$\endgroup\$ Oct 18, 2016 at 11:40
3
\$\begingroup\$

GNU sed 86 Bytes

Includes +1 for -r

:;s,^([^-]*)(\w+)([^-]*-)\2( [^+]*\+)(\w*),\1\5\3\2\4\5,
t;s,-[^-+]*,,;s,\+[^-+]*,,;t

Try it online!

Example:

$ echo 'Hello world -wo -ld +Ea +th'|sed -rf replace.sed
Hello Earth
\$\endgroup\$
3
\$\begingroup\$

PHP, 98 97 bytes

for($s=$argv[$i=1];$v=$argv[++$i];)$r[$v[0]>'+'][]=substr($v,1);echo str_replace($r[1],$r[0],$s);

This challenge describes the exact behaviour of str_replace so for php it's all about making the arrays of replacements. I tried to do it using only one "substring" but that might not be the best solution. Use like:

php -r "for($s=$argv[$i=1];$v=$argv[++$i];)$r[$v[0]>'+'][]=substr($v,1);echo str_replace($r[1],$r[0],$s);" "mississippi" "-is" "-i" "+iz" "+p"

edit: 1 byte saved thanks to Titus

\$\endgroup\$
1
  • \$\begingroup\$ This is probably the shortest thing possible. But $v[0]>'+' saves one byte over $v[0]=='-'. You could also use ord($v)&4 instead. \$\endgroup\$
    – Titus
    Oct 17, 2016 at 19:06
2
\$\begingroup\$

Java 7, 153 133 bytes

String c(String[]a){String r=a[0],z[]=a[1].split(" ?-");for(int i=0;i<z.length;r=r.replace(z[i],a[2].split(" ?[+]")[i++]));return r;}

Ungolfed & test code:

Try it here.

class M{
  static String c(String[] a){
    String r = a[0],
           z[] = a[1].split(" ?-");
    for(int i = 0; i < z.length; r = r.replace(z[i], a[2].split(" ?[+]")[i++]));
    return r;
  }

  public static void main(String[] a){
    System.out.println(c(new String[]{ "Hello world", "-wo -ld", "+Ea +th" }));
    System.out.println(c(new String[]{ "Hello World", "-wo -ld", "+Ea +th" }));
    System.out.println(c(new String[]{ "Hello", "-llo", "+y" }));
    System.out.println(c(new String[]{ "Red", "-R -d", "+Gr +en" }));
    System.out.println(c(new String[]{ "mississippi", "-is -i", "+lz +p" }));
    System.out.println(c(new String[]{ "Football", "-o -a", "+a +i" }));
    System.out.println(c(new String[]{ "mississippi", "-is -i", "+iz +p" }));
  }
}

Output:

Hello Earth
Hello Worth
Hey
Green
mlzslzspppp
Fiitbill
mpzspzspppp
\$\endgroup\$
3
  • \$\begingroup\$ Does this work for the input new String[]{'Rom Ro. Rom", "-Ro." , "+No."}? Just writing something that (hopefully) matches a wrong regex. \$\endgroup\$ Oct 18, 2016 at 5:09
  • \$\begingroup\$ @RomanGräf Yes, works and outputs Rom No. Rom. Btw, you can try it yourself by clicking the Try it here. link in the post, and then fork it. :) \$\endgroup\$ Oct 18, 2016 at 6:45
  • \$\begingroup\$ I know but I'm currently on my mobile. :( \$\endgroup\$ Oct 18, 2016 at 7:29
2
\$\begingroup\$

PHP, 164 Bytes

preg_match_all("#^[^-+]+|-[\S]+|[+][\S]+#",$argv[1],$t);for($s=($a=$t[0])[0];++$i<$c=count($a)/2;)$s=str_replace(trim($a[+$i],"-"),trim($a[$i+$c^0],"+"),$s);echo$s;
\$\endgroup\$
2
\$\begingroup\$

Vim, 25 bytes

qq+dE+r-PdiW:1s<C-R>"-g<CR>@qq@q

Assumes input in this format:

mississippi
-is -i
+lz +p
  • +dE+r-PdiW: Combines - and + into single register, with the + turned into a -.
  • :1s<C-R>"-g: Uses the register as a code snippet, inserted directly into the :s command, with - as the separator.
\$\endgroup\$
0
2
\$\begingroup\$

Convex, 19 bytes

¶:äz{S*"-+"-ä~@\ò}/

Try it online!

\$\endgroup\$
2
\$\begingroup\$

R, 98 94 bytes

Edit: saved 4 bytes thanks to @rturnbull

i=scan(,"");s=i[1];i=gsub("\\+|-","",i[-1]);l=length(i)/2;for(j in 1:l)s=gsub(i[j],i[l+j],s);s

Ungolfed and test cases

Because scan (reads input from stdin) doesn't work properly in R-fiddle I showcase the program by wrapping it in a function instead. Note that the function takes a vector as an input and can be run by e.g.: f(c("Hello world", "-wo", "-ld", "+Ea", "+th")). The gofled program above would prompt the user to input using stdin whereby typing "Hello world" -wo -ld -Ea +th in the console would yield the same result.

Run the code on R-fiddle

f=function(i){
    s=i[1]                                   # Separate first element
    i=gsub("\\+|-","",i[-1])                 # Remove + and - from all elements except first, store as vector i
    l=length(i)/2                            # calculate the length of the vector i (should always be even)
    for(j in 1:l)s=gsub(i[j],i[l+j],s)       # iteratively match element j in i and substitute with element l+j in i
    s                                        # print to stdout
}
\$\endgroup\$
7
  • \$\begingroup\$ Can you provide a test suite link also, please? \$\endgroup\$
    – ʰᵈˑ
    Oct 17, 2016 at 9:23
  • \$\begingroup\$ @ʰᵈˑ added an R-fiddle test suite. Note that the test suite uses a function instead of reading input from stdin as explained in the edited answer. \$\endgroup\$
    – Billywob
    Oct 17, 2016 at 9:59
  • \$\begingroup\$ Is this answer valid, since you have to use " around the input string? \$\endgroup\$
    – rturnbull
    Oct 17, 2016 at 21:06
  • \$\begingroup\$ @rturnbull I don't see why not. Wrapping every entry with quotes and pressing enter would yield the equivalent result (e.g.: "Hello world" => enter => "-wo" => enter => "-ld" => enter => "+Ea" => enter =>"+th") which is usually how strings are read anyways. \$\endgroup\$
    – Billywob
    Oct 17, 2016 at 21:16
  • 1
    \$\begingroup\$ Yeah it's really up to the OP! I personally like your answer as-is, but I was worried that it might be invalid. Looking at answers for other languages it seems like quotes are pretty accepted. While I have your attention, I think you can golf off 4 bytes by changing l=length(i) to l=length(i)/2 and updating the later references to l. \$\endgroup\$
    – rturnbull
    Oct 17, 2016 at 21:57
2
\$\begingroup\$

Haskell, 85 78 bytes

import Data.Lists
g=map tail.words
a#b=foldl(flip$uncurry replace)a.zip(g b).g

Usage example: ("mississippi" # "-is -i") "+lz +p" -> "mlzslzspppp".

How it works:

g=map tail.words              -- helper function that splits a string into a
                              -- list of words (at spaces) and drops the first
                              -- char of each word

                zip(g b).g    -- make pairs of strings to be replaced and its
                              -- replacement
foldl(flip$uncurry replace)a  -- execute each replacement, starting with the
                              -- original string
                              -- -> "flip" flips the arguments of "uncurry replace"
                              --           i.e. string before pair of replacements
                              -- "uncurry" turns a function that expects two
                              --           lists into one that expects a list of pairs

Edit: @BlackCap found 6 bytes to save and I myself another one.

\$\endgroup\$
2
  • \$\begingroup\$ 6 bytes: import Data.Lists;a#b=foldl(uncurry replaceflip)a.zip(g b).g;g=map tail.words \$\endgroup\$
    – BlackCap
    Oct 31, 2016 at 10:52
  • \$\begingroup\$ @BlackCap: Nice, thanks! No need to make flip infix. Standard prefix is one byte shorter. \$\endgroup\$
    – nimi
    Oct 31, 2016 at 17:58
1
\$\begingroup\$

Python 3, 93 byte

def f(s):
  s,m,p=s
  for n,o in zip(m.split(),p.split()):s=s.replace(n[1:],o[1:])
  return s

Try it online!

Input is a list with strings, replacement strings are space separated.

Example input: ['mississippi','-is -i','+iz +p']

\$\endgroup\$
2
  • \$\begingroup\$ Are you able to add a test suite link, please? \$\endgroup\$
    – ʰᵈˑ
    Oct 17, 2016 at 10:08
  • \$\begingroup\$ Link provided and also reduced size a little. \$\endgroup\$ Oct 17, 2016 at 10:14
1
\$\begingroup\$

PowerShell v2+, 90 bytes

param($a,$b,$c)-split$b|%{$a=$a-creplace($_-replace'-'),((-split$c)[$i++]-replace'\+')};$a

Takes input as three arguments, with the - and + strings space-separated. Performs a -split on $b (the -split when acting in a unary fashion splits on whitespace), then loops |%{...} through each of those. Every iteration we're removing the -, finding the next [$i++] replacement string and removing the + from it, and using the -creplace (case-sensitive replacement) to slice and dice $a and store it back into $a. Then, $a is left on the pipeline and output is implicit.

PS C:\Tools\Scripts\golfing> .\letter-replacement-challenge.ps1 'mississippi' '-is -i' '+iz +p'
mpzspzspppp

PS C:\Tools\Scripts\golfing> .\letter-replacement-challenge.ps1 'Hello world' '-wo -ld' '+Ea +th'
Hello Earth

PS C:\Tools\Scripts\golfing> .\letter-replacement-challenge.ps1 'Hello World' '-wo -ld' '+Ea +th'
Hello Worth
\$\endgroup\$
1
\$\begingroup\$

PHP, 106 bytes

for($s=($v=$argv)[$i=1];$i++<$n=$argc/2;)$s=str_replace(substr($v[$i],1),substr($v[$n+$i-1],1),$s);echo$s;

straight forward approach. Run with php -r '<code> <arguments>.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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