The challenge involve simply toggling a string within another string.

Explanation

If the toggle string is a substring of the main string, remove all instances of the toggle string from the main string; otherwise, append the toggle string at the end of the main string.

Rules

  • All string are composed of printable ASCII characters
  • The function should take two parameters: the main string and the toggle string.
  • The main string can be empty.
  • The toggle string cannot be empty.
  • The result should be a string, which can be empty.
  • The shortest answer wins.

Examples

function toggle(main_string, toggle_string){ ... }

toggle('this string has 6 words ', 'now') 
=> 'this string has 6 words now'

toggle('this string has 5 words now', ' now') 
=> 'this string has 5 words'

Tests cases

'','a'          => 'a'
'a','a'         => ''

'b','a'         => 'ba'
'ab','a'        => 'b'

'aba','a'       => 'b'
'ababa', 'aba'  => 'ba'
  • 2
    @KennyLau It was in the sandbox for all of 3 hours. The recommendation is 2 days. – Morgan Thrapp May 20 '16 at 13:18
  • 9
    The recommendation is actually 72 hours. The main page has much more visibility than the Sandbox, so more comments are guaranteed here. That said, this isn't a bad challenge, just has a few rough edges. – AdmBorkBork May 20 '16 at 13:19
  • 2
    So you replace all non-overlapping instances? – Suever May 20 '16 at 13:26
  • 1
    @Jakube Yes, I should limit this to letters and number I think. – nobe4 May 20 '16 at 16:20
  • 1
    No, I think allow nonalphanumerics: it's more challenging that way. – msh210 May 22 '16 at 7:35

33 Answers 33

up vote 5 down vote accepted

Jelly, 7 bytes

œṣȮ⁸e⁹ẋ

Try it online!

How it works

œṣȮ⁸e⁹ẋ  Main link. Arguments: s (string), t (toggle string)

œṣ       Split s at occurrences of t.
  Ȯ      Print the result.
   ⁸e    Check if s occurs in the split s. Yields 1 (true) or 0 (false).
     ⁹ẋ  Repeat t that many times.

Java 8, 80 70 65 34 bytes

t->m->m==(m=m.replace(t,""))?m+t:m

Probably my shortest Java 'codegolf' so far.. xD
with some help from the comments.. ;)

Explanation:

Try it online.

t->m->                     // Method with two String parameters and String return-type
                           // (NOTE: Takes the toggle `t` and main `m` in reversed order)
  m==(m=m.replace(t,""))?  //  If `m` equals `m` with all `t`-substrings removed:
                           //  (And set `m` to `m` with all `t`-substrings removed)
   m+t                     //   Output this new `m` concatted with `t`
  :                        //  Else:
   m                       //   Output just this new `m`
  • 1
    You should be able to save quite a few by changing the if to a ternary. If nothing else, it'll get rid of the "extra" return. – Geobits May 20 '16 at 13:33
  • @Geobits Ah, of course.. I was so enthusiastic that a single method had a 'low' byte count (in terms of java 'codegolfing') that I forgot one of the most obvious codegolfing for ifs and returns.. >.> Thanks, edited. – Kevin Cruijssen May 20 '16 at 13:38
  • 1
    You can save a few more bytes by using a lambda instead of a regular function. – Denker May 20 '16 at 13:47
  • return m=m.replace(t,"")?m+t:m; – Leaky Nun May 20 '16 at 14:14
  • 2
    m==(m=m.replace... – Leaky Nun May 20 '16 at 14:34

MATL, 11 bytes

yyXf?''YX}h

Try it Online!

All test cases

Explanation

            % Implicitly grab the main string
            % Implicitly grab the toggle string
y           % Copy the main string
y           % Copy the toggle string
Xf          % Check to see if the toggle string is present in the main string
?           % If so
    ''YX    % Replace with an empty string
}           % else
    h       % Horizontally concatenate the two strings
            % Implicit end of if...else
            % Implicitly display the result

Python 3, 38 bytes

lambda s,t:(s+t,s.replace(t,""))[t in s]

JavaScript (ES6), 39 37 bytes

(s,t,u=s.split(t).join``)=>u==s?s+t:u

Pyke, 14 bytes

DX{iIXRk:)i!IJ

Try it here!

Given that Pyke has no else structure, I think this is pretty reasonable score

Explanation:

D              -    Duplicate input
 X             -   a,b = ^
  {            -  a in b
   i           - i = ^
    I          - if i:
     XRk:      -  a = b.replace(a,"")
         i!I   - if not i:
            J  -  a = "".join(input)
               - print a

CJam, 9

q~:B/2Be]

Try it online. Thanks jimmy23013 for chopping off 1 byte :)

Explanation:

q~     read and evaluate the input (given as 2 quoted strings)
:B     store the toggle string in B
/      split the main string by the toggle string
2Be]   pad the array of pieces to the right with B, up to length 2 (if shorter)
  • 1
    9 bytes: q~:B/2Be]. – jimmy23013 May 20 '16 at 16:53

Javascript (ECMAScript 6): 47 bytes

(a,b)=>(c=a.replace(RegExp(b,'g'),''))!=a?c:a+b
  • 5
    This can fail if the toggle string contains special characters. For example, ("a", ".") returns "" instead of "a.". – Dennis May 20 '16 at 15:23

Retina, 38 31 bytes

Byte count assumes ISO 8859-1 encoding.

(.+)(?=.*¶\1$)
·
1>`·|¶.+

T`·¶

The trailing linefeed is significant. Input format is both strings separated with a linefeed.

Try it online! The first line allows running several test cases at once (for the test suite, use ; to separate the strings and linefeeds to separate test cases; the first line takes care of the conversion).

Explanation

(.+)(?=.*¶\1$)
·

In this first step we replace all occurrences of the toggle string in the main string with ·. We need to insert these markers so that we can determine afterwards if any substitution happened.

1>`·|¶.+

This is another substitution which removes a · marker, or the second line (including the separating linefeed). However, the 1> is a limit which means that only matches after the first are considered. Hence, if the toggle string did not occur in the main string, we won't have inserted any ·, so the second line will be the first match and won't be removed. Otherwise, we remove the second line along with all but the first marker.

T`·¶

While this uses a transliteration stage, it's also used simply for removing characters. In particular, we move both · and linefeeds. We need the first one, in case there was a match (because then the first · will have been left behind by the previous stage) and we need the second one in case there wasn't a match (to join the two lines together and thereby append the toggle string to the main string).

Python (3.4): 55 54 47 44 Bytes

lambda m,t:m.replace(t,'')if t in m else m+t

Testing:

toggle=lambda m,t:m.replace(t,'')if t in m else m+t
print('', 'a', toggle('','a'))
print('a', 'a', toggle('a','a'))
print('b', 'a', toggle('b','a'))
print('ab', 'a', toggle('ab','a'))
print('aba', 'a', toggle('aba','a'))
print('ababa', 'aba', toggle('ababa','aba'))

The Test output

 a a
a a
b a ba
ab a b
aba a b
ababa aba ba

Using a def would be longer because you have to use a return statement, if it were possible without return it would save 2 Bytes Since explicit declaration of the function is not needed (sorry I didn't know that) 7 Bytes were saved.

  • Nice answer! For our rules, you don't need a name for the function. So you can remove the toggle=. – Picard May 20 '16 at 13:53
  • I just realized, my Test won't work if I don't name the function, but with the toggle= the Tests work – levanth May 20 '16 at 13:57
  • yes, the toggle is needed to test it. But you only need to count from lambda m,t: on. – Picard May 20 '16 at 14:04
  • You can change m+''+t to m+t to save 3 bytes, if I'm not mistaken. – Sherlock9 May 20 '16 at 14:37
  • You're right, I started with m+' '+t to enter a space between them, but after reading the description again I deleted the whitespace but not the '' and the + – levanth May 20 '16 at 14:38

C#, 63

string F(string s,string t)=>s.Contains(t)?s.Replace(t,""):s+t;

Better than Java :)

Test code:

public static void Main()
{
    Console.WriteLine(F("", "a"));
    Console.WriteLine(F("a", "a"));
    Console.WriteLine(F("b", "a"));
    Console.WriteLine(F("ab", "a"));
    Console.WriteLine(F("aba", "a"));
    Console.WriteLine(F("ababa", "aba"));
    Console.ReadLine();
}

Output:

a

ba
b
b
ba

Pyth, 13 11 10 bytes

?/Qz:Qzk+z

Test suite.

Input format: first string in quotes, second string without quotes.

This is also 10 bytes:

?tJcQzsJ+z

Test suite.

This is 11 bytes:

pscQz*!}zQz

Test suite.

Previous 13-byte solution:

?:IQzk+Qz:Qzk

Test suite.

  • 1
    Also 11 bytes: ?}zQ:Qzk+Qz – Blue May 20 '16 at 13:37

Jolf, 12 bytes

?=iγρiIE+iIγ

Or, if we must include regex-sensitive chars:

?=iγρiLeIE+iIγ

Try it here!

Explanation

?=iγρiIE+iIγ    if(i === (γ = i.replace(I, E))) alert(i + I); else alert(γ);
  i                i
 =                   ===
    ρ                          .replace( ,  )
     iI                       i         I 
       E                                   E
   γ                     (γ =                )
?               if(                           )
        +iI                                     alert(i + I);
                                                              else
           γ                                                       alert(γ);

JavaScript (ES6), 37 Bytes

(m,t)=>(w=m.split(t).join``)==m?m+t:w

Slightly shorter than @nobe4 's answer by taking advantage of split and join

Racket, 70 bytes

Pretty straight forward.

(λ(s t)((if(string-contains? s t)string-replace string-append)s t""))

Scala, 72 70 bytes

def x(m:String,s:String)={val r=m.replaceAll(s,"");if(r==m)m+s else r}

Online interpreter: www.tryscala.com

  • 1
    Welcome to Programming Puzzles & Code Golf! I don't know Scala, but I think you can remove the spaces around if(r==m). – Dennis May 20 '16 at 15:35
  • Yeah you are right – Avis May 21 '16 at 8:54

Oracle SQL 11.2, 66 bytes

SELECT DECODE(:1,s,s||:2,s)FROM(SELECT REPLACE(:1,:2)s FROM DUAL);

Perl, 37 30 bytes

{$_=shift;s/\Q@_//g?$_:"$_@_"}

Regular expressions inside the toggle string are not evaluate because of the quoting with \Q...\E.

sub F and \E are removed according to the comment by msh210.

It is not entirely free of side effects because of setting $_. Using a local variable will cost six additional bytes:

{my$a=shift;$a=~s/\Q@_//g?$a:"$a@_"}

On the other hand, with switched input parameters two bytes can be saved by using pop instead of shift (28 bytes):

{$_=pop;s/\Q@_//g?$_:"$_@_"}

Test file:

#!/usr/bin/env perl

sub F{$_=shift;s/\Q@_//g?$_:"$_@_"}

sub test ($$$) {
  my ($m, $t, $r) = @_;
  my $result = F($m, $t);
  print "F('$m', '$t') -> '$result' ",
    ($result eq $r ? '=OK=' : '<ERROR>'), " '$r'\n";
}
test '', 'a', 'a';
test 'a', 'a', '';
test 'b', 'a', 'ba';
test 'ab', 'a', 'b';
test 'aba', 'a', 'b';
test 'ababa', 'aba', 'ba';
test 'ababa', 'a*', 'ababaa*';
test 'foobar', '.', 'foobar.';
__END__

Test result:

F('', 'a') -> 'a' =OK= 'a'
F('a', 'a') -> '' =OK= ''
F('b', 'a') -> 'ba' =OK= 'ba'
F('ab', 'a') -> 'b' =OK= 'b'
F('aba', 'a') -> 'b' =OK= 'b'
F('ababa', 'aba') -> 'ba' =OK= 'ba'
F('ababa', 'a*') -> 'ababaa*' =OK= 'ababaa*'
F('foobar', '.') -> 'foobar.' =OK= 'foobar.'
  • perlsub says "The signature is part of a subroutine's body. Normally the body of a subroutine is simply a braced block of code." Thus, you can omit sub F from your byte count. Also, you should be able to use pop instead of shift (by reversing the order of the inputs, natch), saving two bytes. (Untested.) Finally, you should be able to omit the \E, saving two more bytes. (Also untested.) – msh210 May 22 '16 at 7:23
  • @msh210 Thanks, your tips saved seven bytes. I do not see, how pop instead of shift can help, because $_ should be the first argument to avoid $_[1]=~s/.../. The order of input arguments is fixed by the question AFAIK. – Heiko Oberdiek May 22 '16 at 9:59
  • The order of input arguments is not fixed by the question afaict. – msh210 May 22 '16 at 14:50

C# (58 bytes)

string F(string s,string t)=>s==(s=s.Replace(t,""))?s+t:s;

It uses an inline assignment to shave a few bytes off

  • Hello, and welcome to PPCG! Great first post! I don't use C# much, but can't you do var s,t or var s,var t instead of string? – NoOneIsHere May 22 '16 at 19:50
  • Thanks! Sadly var can only be used in places where the type is known at compile time, so it can't be used in method signatures. You could use dynamic, but it's 1 character longer that string – Blue0500 May 22 '16 at 22:00
  • What about var F(string s, string t? That can be inferred... – NoOneIsHere Jul 7 '16 at 1:00

bash + sed, 28 bytes

sed "s/$2//g;t;s/$/$2/"<<<$1

The script lives in a toggle-string.bash file, which we call with bash toggle-string.bash mainstring togglestring.

s/$2//g removes the toggle string from the main string

t jumps to the end if the previous substitution was successful (ie. the main string contained the toggle string)

/$/$2/ adds the toggle string at the end ($), if we didn't jump to the end

bash is required for the herestring

  • This won't work if the toggle string contains special characters. – Dennis May 23 '16 at 15:40

Julia, 33 31 bytes

s|t=(r=replace(s,t,""))t^(s==r)

Try it online!

PowerShell v2+, 47 bytes

param($a,$b)(($c=$a-replace$b),"$a$b")[$c-eq$a]

Takes input $a,$b and then uses a pseudo-ternary (... , ...)[...] statement to perform an if/else. The inner parts are evaluated first to form an array of two elements. The 0th is $a with all occurrences of $b -replaced with nothing, which is stored into $c. The 1st is just a string concatenation of $a and $b.

If $c is -equal to $a, meaning that $b wasn't found, that's Boolean $true or 1, and so the 1st element of the array (the concatenation) is chosen. Else, it's Boolean $false, so we output $c, the 0th element.

Note that -replace is greedy, so it will replace from the left first, meaning the ababa / aba test case will properly return ba.

Java 8, 65 bytes

BinaryOperator<String>l=(m,t)->m.contains(t)?m.replace(t,""):m+t;

The same logic as the Java 7 solution, written with a lambda.

Try it here

Ruby, 33 bytes 27 bytes (28 if using global subtitution) definitely 28 bytes

->u,v{u[v]?u.gsub(v,''):u+v}

Mathematica, 45 bytes

If[StringContainsQ@##,StringDelete@##,#<>#2]&

Anonymous function that takes the main string and the toggle string (in that order) and returns the result. Explanation:

                                            &  Anonymous function returning...

If[StringContainsQ@##,               ,     ]    if its first argument contains
                                                its second argument, then...
                      StringDelete@##            its first argument with its
                                                 second argument removed, else...
                                      #<>#2      its second argument appended to
                                                 its first argument.

TSQL, 143 129 121 Bytes

DECLARE @1 VARCHAR(10)='',@2 VARCHAR(10)='a'SELECT CASE WHEN @1 LIKE'%'+@2+'%'THEN REPLACE(@1,@2,'')ELSE CONCAT(@1,@2)END

Readable:

   DECLARE @1 VARCHAR(10) = ''
    , @2 VARCHAR(10) = 'a'

SELECT CASE WHEN @1 LIKE '%' + @2 + '%'
            THEN REPLACE(@1, @2, '')
            ELSE CONCAT (@1, @2)
            END

Live Demo

114 Bytes with strictly 1 character input

DECLARE @1 CHAR(1) = 'a'
    , @2 CHAR(1) = '.'

SELECT CASE WHEN @1 LIKE '%' + @2 + '%'
            THEN REPLACE(@1, @2, '')
            ELSE CONCAT (@1, @2) END
  • Hello, and welcome to PPCG! Great answer! – NoOneIsHere May 20 '16 at 16:10

TSQL(Sqlserver 2012), 49 bytes

DECLARE @ VARCHAR(10) = 'hello',@x VARCHAR(10) = 'o'

PRINT IIF(@ LIKE'%'+@x+'%',REPLACE(@,@x,''),@+@x)

Try it online!

Ruby, 35 37 28 bytes

->m,t{m[t]?m.gsub(t,''):m+t}

Hooray for string interpolation! It even works in regexes. The rest is simple: if the string in t matches to m, replace t with '', else return m+t.

Edit: Fixed a bug.

Edit: I applied Kevin Lau's suggestion, but it appears that I have reached the same algorithm as the one used in Luis Masuelli's answer.

  • This can fail if the toggle string contains special characters. For example, ("a", ".") returns "a" instead of "a.". – Dennis May 20 '16 at 15:21
  • m[t] is much shorter than m.include?(t) and still checks for inclusion within strings. – Value Ink May 20 '16 at 18:26

k (23 bytes)

{$[#x ss y;,/y\:x;x,y]}

Examples:

k){$[#x ss y;,/y\:x;x,y]}["aba";"a"]
,"b"
k){$[#x ss y;,/y\:x;x,y]}["this string has 6 words ";"now"]
"this string has 6 words now"
k){$[#x ss y;,/y\:x;x,y]}["this string has 5 words now";"now"]
"this string has 5 words "
k){$[#x ss y;,/y\:x;x,y]}["ababa";"ba"]
,"a"
k){$[#x ss y;,/y\:x;x,y]}["";"a"]
,"a"

Kotlin, 61 Bytes

{m:String,t:String->var n=m.replace(t,"");if(m==n)m+t else n}

This is would be shorter if assignment was an expression in Kotlin,and parameters were mutable,and there was a ternary conditional operator, sadly this isn't the case :(

Try it Online!

UnGolfed

fun t(m:String, t:String):String{
    var n=m.replace(t, "")
    return if(m==n)m+t else n
}

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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