String Shenanigans

6

1

Challenge

In this challenge, you are to code in any language a program or function that will take a string and replace certain characters within it with different characters.

Input

The input is the same for both functions and full programs:

[string] [char1] [char2]
  • string will be an indefinite line of characters surrounded by quotation mars, such as "Hello, World!" or "1 plus 2 = 3".

  • char1 will be a single character within string.

  • char2 will be a single character not necessarily in string.

Output

[modified string]

Your output will take string and replace all instances of char1 with char2, then output the result as modified string. Case should be ignored, so the input "yolO" o u should output yulu.

Examples

Input

"Hello, World!" l r

Output

Herro, Worrd!

Input

"Slithery snakes slurp Smoothies through Silly Straws" s z

Output

zlithery znakez zlurp zmoothiez through zilly ztrawz

Input

"Grant Bowtie: Only the best future bass artist ever" : -

Output

Grant Bowtie- Only the best future bass artist ever

Input

"019 + 532 * 281 / ? = waht/?" / !

Output

019 + 532 * 281 ! ? = waht!?

Other details

This is code golf, so the shortest answer (in bytes) at the end of the week (the 14th of September) wins. Also, anything not specified in this challenge is fair game, meaning that stuff I don't explain is up to you.

The_Basset_Hound

Posted 2015-09-08T01:35:10.560

Reputation: 1 566

I figure the two characters can be upper case as well? And if the first of the two is upper case, it would still match both lower and upper case characters in the string? – Reto Koradi – 2015-09-08T02:34:06.077

4Are functions allowed? – Downgoat – 2015-09-08T03:22:55.087

To add to vihan's comment, note that per our defaults, functions or full programs are both okay.

– Alex A. – 2015-09-08T03:25:07.317

2@AlexA. Isn't that only if it's not specified? In this case, it says "a program". In the past, that meant that you had to provide a full program. – Reto Koradi – 2015-09-08T03:27:02.293

@RetoKoradi - unfortunately, different people use the term "program" differently. So "in the past" is only relevant if it was the same person (the_basset_hound). – Glen O – 2015-09-08T03:42:25.363

What about the quotes in the input? I guess they have to be removed, haven't they? – Cabbie407 – 2015-09-08T04:40:10.203

@RetoKoradi All replaced characters should be lowercase, regardless of the case of the two characters. – The_Basset_Hound – 2015-09-08T05:02:55.227

2@vihan Functions are allowed. – The_Basset_Hound – 2015-09-08T05:03:18.470

1@Cabbie407 The quotes will need to be accounted for, yes. – The_Basset_Hound – 2015-09-08T05:05:06.207

6So the second character can be upper case, and the replaced character is lower case? That doesn't make much sense to me. So if functions are allowed, but it specifically says that the input string has quotes, will the function receive a string that has quotes inside the string? Well, frankly, I'm probably done with this challenge anyway. Changing about 3 rules after there are already 10 answers is very unfortunate. – Reto Koradi – 2015-09-08T05:34:05.497

4That part about all replacements needing to be lowercase is new. The original statement said, that case should be ignored. For me this means, that lower and upper case letters should be replaced, but not that I should change the replacement letter... – Cabbie407 – 2015-09-08T05:35:35.327

Does input have to come from stdin or from command line arguments? If stdin, do the three items have to be separated by a single space each, or are other delimiters acceptable? – ThisSuitIsBlackNot – 2015-09-08T17:17:55.963

1@RetoKoradi How about this (and I'll put this and other info in the question): Anything not specified about the challenge is fair game. – The_Basset_Hound – 2015-09-08T22:31:00.947

Answers

6

Pyth, 10 bytes

XQr*2w4*2w

Try in online: Demonstration or Test Suite

Explanation:

 Q             read a line and evaluates (reads a string with quotes)
     w         reads a char: a (actually reads a line)
   *2          make it twice as long: aa (repeat the char)
  r   4        capitalize this string: Aa
       *2w     read another char and repeat it: bb
X              replace the letters Aa by bb in Q

Jakube

Posted 2015-09-08T01:35:10.560

Reputation: 21 462

12

Vim, 18 keystrokes

$bD:s/<C-R>"<Left><BS>/<Right>/i<CR>x$x

Assuming the cursor is on the first column of the first line, and the open file contains this:

"yolO" o u

The file will end up containing:

"yulu" 

orlp

Posted 2015-09-08T01:35:10.560

Reputation: 37 067

1+1 for Vim ... not something oft-seen :) – AdmBorkBork – 2015-09-08T14:35:57.197

1Your ending file shouldn't contain the quotation marks – Nathan Merrill – 2015-09-09T13:20:42.373

@NathanMerrill Fixed. – orlp – 2015-09-13T05:38:41.700

10

JavaScript ES6, 28 bytes

(s,a,b)=>s.replace(a,b,'gi')

Firefox only as it uses a mozilla-specific feature.

Downgoat

Posted 2015-09-08T01:35:10.560

Reputation: 27 116

That was quick. I appear to have made this too easy again... – The_Basset_Hound – 2015-09-08T01:46:48.027

8Is it correct to use 3 arguments instead of 1 string? – Qwertiy – 2015-09-08T09:44:56.563

6

Retina, 29 bytes

i`(.)(?=.*\1 (.)$)|"|....$
$2

For scoring purposes each line goes in a separate file, but for convenience you can run the above from a single file with the -s flag.

As this is just a single regex replacement, you can test it here.

The regex consists of three parts, one to do the substitution and two to clean up the rest of the input. This is the substitution part:

(.)       # Match a character and capture it in group 1.
(?=       # Lookahead to ensure that this is the character we're searching for.
  .*      # Consume arbitrary characters to move to the end of the string.
  \1 (.)$ # Ensure we can match the captured character, then a space, then
          # another character and then the end of input. That other character
          # is captured in group 2.
)

This match is replaced by $2, i.e. the character to be substituted in.

The other two possibilities are either to match a ", or to match the last four characters of the input. In either case group two is empty, so the replacement string $2 evaluates to an empty string and the match is simply removed from the input. This cleans up the quotes and the characters at the end.

i` simply activates case insensitive matching.

Martin Ender

Posted 2015-09-08T01:35:10.560

Reputation: 184 808

1How does this work? – mbomb007 – 2015-09-08T21:59:09.520

@mbomb007 Edited. Let me know if you have further questions. – Martin Ender – 2015-09-09T09:20:53.473

5

gawk - 48

IGNORECASE=gsub(/"/,_),gsub($(NF-1),$NF)+(NF-=2)

That IGNORECASE hurts...

How to use

In bash enter: awk 'IGNORECASE=gsub(/"/,_),gsub($(NF-1),$NF)+(NF-=2)'

Then enter a string in quotes and the two characters. In front of some characters ("[" and "(" I know of) you have to enter a backslash, because awk would try to interpret them as regular expression instead.

Cabbie407

Posted 2015-09-08T01:35:10.560

Reputation: 1 158

This doesn't work. – User112638726 – 2015-09-09T09:52:29.573

Hmm... it works with gawk and mawk... – Cabbie407 – 2015-09-09T11:23:53.017

Doesn't work with my Gawk, what version are you using? Why is there a comma between the 2 gsubs ? Nvm, didn't work properly with STDIN because i didn't escape the quotes... Still don't need that comma though or the + as they are doing nothing. – User112638726 – 2015-09-09T12:24:25.383

1Few less characters awk 'IGNORECASE=gsub(/"/,x)gsub($(NF-1),$NF)(NF-=2)' – User112638726 – 2015-09-09T12:27:13.317

I use gawk 4.1.1, but since this works with the mawk that comes with ubuntu I figured it would work with any awk. The comma is normally used to specify a range pattern. http://www.math.utah.edu/docs/info/gawk_9.html#SEC92 I use it here just because it works. ;)

– Cabbie407 – 2015-09-09T12:29:20.450

1Oh, great, thanks. :) This does not set IGNORECASE for the first input. But I got fooled by the syntax highlighting in my editor for that quote regexp ;) – Cabbie407 – 2015-09-09T12:35:04.013

Yep, just realised it would be set a value of 267 and probably wrap :( – User112638726 – 2015-09-09T12:48:56.290

4

Octave, 28

An anonymous function using built in functions.

@(W,T,F)strrep(lower(W),T,F)

Assuming it is stored in f we can call it as follows:

f('Slithery snakes slurp Smoothies through Silly Straws','s','z')

ಠ_ಠ

Posted 2015-09-08T01:35:10.560

Reputation: 430

Word list, Template, Fill-in? – ಠ_ಠ – 2015-09-13T09:16:13.733

3

R, 28

function(s,c,r)gsub(c,r,s,T)

Had the order of the arguments been (c,r,s), I thought of doing

functional::Curry(gsub,i=T)

functional is a 3rd-party package whose Curry functional allows redefining function arguments: here, returns a function like gsub but with the modified ignore.case = TRUE.

flodel

Posted 2015-09-08T01:35:10.560

Reputation: 2 345

You can save two bytes using positional parameters rather than named parameters with partial matching. That is, you can use gsub(c,r,s,T) since ignore.case is the fourth positional argument. – Alex A. – 2015-09-08T02:16:31.873

Also this is 30 bytes, not 29.

– Alex A. – 2015-09-08T02:18:41.243

1For the same length function(s,c,r)chartr(c,r,s) – MickyT – 2015-09-08T03:24:32.103

@MickyT, but chartr is case-sensitive. – flodel – 2015-09-10T23:04:55.633

My bad sorry. I didn't think it through properly. – MickyT – 2015-09-10T23:10:00.413

3

CJam, 18 17 bytes

Kind of awkward handling the quotes and upper vs. lower case. But I believe it works for all cases:

l'"%~S%(eu_el+\er

Try it online

Thanks to @Dennis for golfing 1 byte.

Note that this is a full program that takes the input exactly as specified in the question. I can make this shorter if the input requirements are interpreted more flexibly.

Explanation:

l     Get input.
'"%   Split at quotes. This separates the string from the remaining arguments,
      and gets rid of the quotes.
~     Unwrap the list. We now have two strings on the stack, the input text
      and a string containing the two letters.
S%    Split the string containing the two letters.
(     Pop off the first ("source") letter.
eu    Convert it to upper case.
_el   Copy and convert to lower case.
+     Concatenate the two, giving us a string with upper and lower case.
\     Swap the second ("target") letter to top.
er    Transliterate.

Reto Koradi

Posted 2015-09-08T01:35:10.560

Reputation: 4 870

1You don't need the last ~. The result won't be a string, but the output won't look different. – Dennis – 2015-09-08T03:57:27.257

3

PowerShell, 33 30 Bytes

param($a,$b,$c)$a-replace$b,$c

Expects input via command-line argument. PowerShell has many built-in case-insensitive operators that just tack on an i in front of the usual operator -- here as -ireplace instead of -replace -- so the case-insensitive matching was actually pretty easy.

PS C:\Tools\Scripts\golfing> .\string-shenanigans.ps1 "Hello, World!" l r
Herro, Worrd!

PS C:\Tools\Scripts\golfing> .\string-shenanigans.ps1 "Slithery snakes slurp Smoothies through Silly Straws" s z
zlithery znakez zlurp zmoothiez through zilly ztrawz

PS C:\Tools\Scripts\golfing> .\string-shenanigans.ps1 "019 + 532 * 281 / ? = waht/?" / !
019 + 532 * 281 ! ? = waht!?

Saved 3 bytes thanks to briantist

AdmBorkBork

Posted 2015-09-08T01:35:10.560

Reputation: 41 581

You can make this shorter: param($a,$b,$c)$a-replace$b,$c . Powershell is case insensitive by default, no need to be explicit with -ireplace here, saves 1 byte, and by removing () from the replace you can save 2 more bytes. – briantist – 2015-09-08T21:35:02.183

@briantist That's a good point. One of the test cases I came up with yesterday broke without the i, but now I can't seem to duplicate that. And good call on removing the parens, too. I miss those more often than not. Regarding the regex ... the input requirements explicitly list "single character" so unless $b is a ., we'll be fine. – AdmBorkBork – 2015-09-09T13:11:30.387

You're correct; I've removed my comments about the regex, it's not an issue. – briantist – 2015-09-09T18:40:48.423

3

Scala, 59 bytes

(s:String,a:Char,b:Char)=>(s"(?i)$a"r).replaceAllIn(s,""+b)

An anonymous function that uses s"" alongwith ""r to dynamically build a case-insensitive regex.

Jacob

Posted 2015-09-08T01:35:10.560

Reputation: 1 582

3

Ruby, 17 bytes

f=->s,*r{s.tr *r}

For example:

> f["Hello there!", ?e, ?a]
=> Hallo thara!

daniero

Posted 2015-09-08T01:35:10.560

Reputation: 17 193

2

Pyth, 7 19? / 15 bytes

jwcjrz1cwrz0rz1

Example Input

(My second Pyth program, ever). Any tips on golfing are welcome. A lot of the bytes are going to the repeated rz1/rz0. I could chop some of these I could be guaranteed the case.


If quotes are required, a slightly larger 19-byte program handles that:

jwcjrz1c:w1_1rz0rz1

Explanation:

This basically. Takes a string:

Slithery snaKEs

Then, chops all lowercase instances of the the character to replace.

['Slithery ','naKE','']

Then joins with the uppercase instance:

Slithery SnaKES

Then chops on the uppercase instance:

['','lithery ','naKE']

Then joins with the new character:

qlithery qnaKEq

Downgoat

Posted 2015-09-08T01:35:10.560

Reputation: 27 116

no it doesn't. It lower cases the entire thing. – Maltysen – 2015-09-08T02:36:53.350

@Maltysen fixed – Downgoat – 2015-09-08T02:48:01.533

This does not take the specified input format. All 3 inputs are on a single line, in the given order. More importantly, the input string is in quotes, while the output string is not. Just try copying and pasting the sample inputs to see if your solutions work or not. – Reto Koradi – 2015-09-08T03:14:30.650

@RetoKoradi I don't think input is that strict. If that were true majority of the answers would work. – Downgoat – 2015-09-08T03:15:49.240

1The order might be flexible, not sure how the rules would handle that. But it clearly says "an indefinite line of characters surrounded by quotation marks". So that part is definitely not optional. – Reto Koradi – 2015-09-08T03:17:21.517

@RetoKoradi Hm, I justified myself from this answer but I'll modify the code to work with that

– Downgoat – 2015-09-08T03:18:53.777

2

Pyth - 11 bytes

A simple regexp solution with case insensitive. Will try to translate to Retina if I get it to compile.

:Q+"(?i)"ww

Test Suite.

Maltysen

Posted 2015-09-08T01:35:10.560

Reputation: 25 023

I don't think this meets the input requirements. It says that "an indefinite line of characters surrounded by quotation marks", while the output does not have quotation marks. If I run your code with quotation marks, they also show up in the output. – Reto Koradi – 2015-09-08T03:21:12.493

1@RetoKoradi sorry, fixing. – Maltysen – 2015-09-08T03:37:17.683

1It looks like we don't have consensus on the input requirements. Some people interpret them differently. – Reto Koradi – 2015-09-08T03:47:23.063

2

mSL, 68 bytes

$replace($gettok($1-,-3-1,32),$gettok($1-,-2,32),$gettok($1-,-1,32))

Denny

Posted 2015-09-08T01:35:10.560

Reputation: 31

2

C#, 93 120 124 123 bytes

class A{static void Main(string[]a){System.Console.Write(a[0].Replace(a[1].ToLower(),a[2]).Replace(a[1].ToUpper(),a[2]));}}

Not sure if I can golf this much better than this, but surprisingly low byte count for C# =D

EDIT: Thanks, Reto Koradi for pointing out the case sensitivity.

EDIT 2: More stuff I missed out on. Maybe doing this during a break in work isn't the best time.

rp.kelly

Posted 2015-09-08T01:35:10.560

Reputation: 91

Does this replace both upper and lower case letters? I don't know C# at all, but I would be surprised if a simple Replace() method replaces in a case insensitive way. – Reto Koradi – 2015-09-08T15:56:35.340

>

  • Why do you assume that the char to replace in in lower case? 2. Why are you writing the full program if you can write a function? 3. You don't need using if use string and System.Console. Anyway, I think, it can be ignored in case of a function.
  • < – Qwertiy – 2015-09-08T16:15:26.587

    Thanks for the tip regarding the using @Qwertiy. Dunno what I was thinking there. In terms of writing a program, the question is asking for a program. – rp.kelly – 2015-09-08T16:28:39.967

    "a program or function" in current question text. – Qwertiy – 2015-09-08T16:33:28.187

    1string with lowercase first letter. With uppercase one it requires System. And you can remove space after []. – Qwertiy – 2015-09-08T16:34:10.597

    1By the way - great idea to allow command line to parse the string. – Qwertiy – 2015-09-08T16:37:25.930

    2

    Bash 4.0+, 21 bytes

    Command-line arguments.

    tr ${2^}${2,} $3<<<$1
    

    Not that Charles

    Posted 2015-09-08T01:35:10.560

    Reputation: 1 905

    2

    C++ 11, Stand-alone: 213 202 198 bytes

    Since I haven't seen a solution on C++ yet, I decided to try something myself. This is my first version and I will try to optimize it later.

    Source code running:

    Live Version: 213 202 198 bytes

    #include <algorithm>
    #include <iostream>
    using namespace std;int main(){string a;getline(cin,a);char b,c;cin.get(b);cin.get(c);replace_if(begin(a),end(a),[b](char d){return!((d-b)%32);},c);cout<<a;}
    

    .

    Only the replace function: 121 110 107 bytes

    getline(cin,a);cin.get(b);cin.get(c);replace_if(begin(a),end(a),[b](char d){return!((d-b)%32);},c);cout<<a;
    

    .

    Feedback is welcome.

    wendelbsilva

    Posted 2015-09-08T01:35:10.560

    Reputation: 411

    2

    Shell 15 bytes:

    sed s/$1/$2/gi
    

    Save as submission.sh and run as:

    $ echo "Hello, World" | ./submission.sh h e
    eello, World
    

    Explanation:

    sed (stream editor) has a substitute command, which parses standard input and substitutes string $1 for string $2. The g modifier substitutes globally in the input string, and i modifier produces a case-insensitive match.

    Old Solution:

    Shell, 14 bytes submission_1.sh

    tr $2 $3<<<$1
    

    Call with

    $ ./submission_1.sh 'hello there!lgge lfewf lger3%#@ %@#T @EG' l r
    herro there!rgge rfewf rger3%#@ %@#T @EG
    

    Alternate, Shell 9 bytes: submission_2.sh (May be too rule-bendy)

    tr $1 $2
    

    Call with

    $ ./submission_2.sh l r <<<'hello there!lgge lfewf lger3%#@ %@#T @EG'
    herro there!rgge rfewf rger3%#@ %@#T @EG
    

    Explanation

    tr by default (without any flags) replaces all chars in the first set with the chars in the second set, completing the operation with the data on standard input.

    I'm using this to my advantage by calling TR with the arguments in the correct order, and (in the alternate submission) taking advantage of the handling of standard input by Bourne Shell (sh) to pass standard input to tr without any additional code.

    Tyzoid

    Posted 2015-09-08T01:35:10.560

    Reputation: 692

    This doesn't seem to comply with “Case should be ignored, so the input "yolO" o u should output yulu.” – manatwork – 2015-09-09T09:48:50.700

    WRT your new solution, does the input not all have to be a single list of args ? – User112638726 – 2015-09-09T13:30:37.700

    @User112638726 It accepts three args, two presented on the command line, and one presented on standard input. Does this answer your question? – Tyzoid – 2015-09-09T20:12:00.450

    2

    Sed, 43 Chars

    :;s/(.)(.*\1 (.))$/\3\2/I;t;s/(. .$|")//g
    

    Invoked with the -r flag for extended regex.

    User112638726

    Posted 2015-09-08T01:35:10.560

    Reputation: 201

    The flag actually costs 3 bytes (one of the surrounding spaces is counted as well). That is, unless you would invoke with sed with something like -e anyway and adding the flag would turn this into -re in which case you'd only count 1 byte. See here, section "Special invocations" for the official consensus.

    – Martin Ender – 2015-09-09T13:05:42.533

    @MartinBüttner Ok thanks,updated :) – User112638726 – 2015-09-09T13:16:14.577

    @MartinBüttner Would using a flag to indicate that it should be run as a script file be counted? What about c++ compiler flags etc? – User112638726 – 2015-09-09T13:34:23.850

    I think flags to run the code from the file would be considered standard and not counted. Compiler flags on the other hand generally are counted (except stuff that you need anyway like linker flags). – Martin Ender – 2015-09-09T13:39:23.177

    2

    Python, 58 bytes

    Uses case-insensitive regex for substitution.

    from re import*
    lambda s,t,u:compile(escape(t),I).sub(u,s)
    

    mbomb007

    Posted 2015-09-08T01:35:10.560

    Reputation: 21 944

    1

    Javascript ES6, 54 chars

    f=s=>s.replace(/(.)(?=.* \1 (.)$)/ig,"$2").slice(1,-5)
    

    Qwertiy

    Posted 2015-09-08T01:35:10.560

    Reputation: 2 697

    1

    PHP, 44 Bytes

    <?=str_ireplace($argv[2],$argv[3],$argv[1]);
    

    Called from the command line via php golf.php "Grant Bowtie: Only the best future bass artist ever" : -

    S22h

    Posted 2015-09-08T01:35:10.560

    Reputation: 151

    1

    Python 2.7, 117 bytes

    def r(s): print ''.join([list(s)[-1]  if x.lower() == list(s)[-3] else x if x != '\"' else '' for x in list(s)][:-4])
    

    Python certainly won't compare to other golfing languages for this challenge, but nothing beats it for list (in)comprehensions.

    If you want it to be a 'standalone' program it increases the size to about 120

    import sys
    if __name__ == "__main__":
      l, y, z = sys.argv[1:]
      print ''.join([z  if x.lower() == y else x for x in l])
    

    Nahkki

    Posted 2015-09-08T01:35:10.560

    Reputation: 111

    1

    Hey, welcome to PPCG! Your code can be shortened a bunch by dropping whitespace and converting it to a lambda. I also believe you can take the input as 3 separate arguments, which would shorten your code again. Happy golfing! :)

    – FryAmTheEggman – 2015-09-08T19:26:12.883

    1

    Shell, 34 27 35 bytes

    #!/bin/sh
    echo $1|sed "s/$2/$3/gi"
    

    Shaun H

    Posted 2015-09-08T01:35:10.560

    Reputation: 732

    1

    Lua, 36 bytes

    a=arg[1]:gsub(arg[2],arg[3])print(a)
    

    Trebuchette

    Posted 2015-09-08T01:35:10.560

    Reputation: 1 692

    This doesn't seem to comply with “Case should be ignored, so the input "yolO" o u should output yulu.” – manatwork – 2015-09-09T13:46:23.290

    1

    Gema, 40 characters

    "*" ? ?=@subst{\\C@quote{?}=@quote{?};*}
    

    Sample run:

    bash-4.3$ gema '"*" ? ?=@subst{\\C@quote{?}=@quote{?};*}' <<< '"Hello, World!" l r'
    Herro, Worrd!
    

    manatwork

    Posted 2015-09-08T01:35:10.560

    Reputation: 17 865

    1

    O, 31 bytes

    i`' /l3-{' \++}d`'"-"(?i)"@+@%p
    

    kirbyfan64sos

    Posted 2015-09-08T01:35:10.560

    Reputation: 8 730

    0

    Perl, 33 chars (without !#) 48 (including !#)

    #!/usr/bin/perl
    ($_,$b,$c)=@ARGV;
    s/$b/$c/i;
    print;
    

    My first golf, one of my first perl programs. Probably could be golfed a little more

    Bald Bantha

    Posted 2015-09-08T01:35:10.560

    Reputation: 463