17
\$\begingroup\$

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'
\$\endgroup\$
9
  • 2
    \$\begingroup\$ @KennyLau It was in the sandbox for all of 3 hours. The recommendation is 2 days. \$\endgroup\$ Commented May 20, 2016 at 13:18
  • 10
    \$\begingroup\$ 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. \$\endgroup\$ Commented May 20, 2016 at 13:19
  • 2
    \$\begingroup\$ So you replace all non-overlapping instances? \$\endgroup\$
    – Suever
    Commented May 20, 2016 at 13:26
  • 1
    \$\begingroup\$ @Jakube Yes, I should limit this to letters and number I think. \$\endgroup\$
    – nobe4
    Commented May 20, 2016 at 16:20
  • 1
    \$\begingroup\$ No, I think allow nonalphanumerics: it's more challenging that way. \$\endgroup\$
    – msh210
    Commented May 22, 2016 at 7:35

33 Answers 33

11
\$\begingroup\$

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`
\$\endgroup\$
7
  • 1
    \$\begingroup\$ 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. \$\endgroup\$
    – Geobits
    Commented May 20, 2016 at 13:33
  • \$\begingroup\$ @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. \$\endgroup\$ Commented May 20, 2016 at 13:38
  • 1
    \$\begingroup\$ You can save a few more bytes by using a lambda instead of a regular function. \$\endgroup\$
    – Denker
    Commented May 20, 2016 at 13:47
  • \$\begingroup\$ return m=m.replace(t,"")?m+t:m; \$\endgroup\$
    – Leaky Nun
    Commented May 20, 2016 at 14:14
  • 2
    \$\begingroup\$ m==(m=m.replace... \$\endgroup\$
    – Leaky Nun
    Commented May 20, 2016 at 14:34
8
\$\begingroup\$

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
\$\endgroup\$
6
\$\begingroup\$

Python 3, 38 bytes

lambda s,t:(s+t,s.replace(t,""))[t in s]
\$\endgroup\$
5
\$\begingroup\$

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.
\$\endgroup\$
4
\$\begingroup\$

JavaScript (ES6), 39 37 bytes

(s,t,u=s.split(t).join``)=>u==s?s+t:u
\$\endgroup\$
3
\$\begingroup\$

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
\$\endgroup\$
3
\$\begingroup\$

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)
\$\endgroup\$
1
  • 1
    \$\begingroup\$ 9 bytes: q~:B/2Be]. \$\endgroup\$
    – jimmy23013
    Commented May 20, 2016 at 16:53
2
\$\begingroup\$

Javascript (ECMAScript 6): 47 bytes

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

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).

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

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.

\$\endgroup\$
5
  • \$\begingroup\$ Nice answer! For our rules, you don't need a name for the function. So you can remove the toggle=. \$\endgroup\$
    – Riker
    Commented May 20, 2016 at 13:53
  • \$\begingroup\$ I just realized, my Test won't work if I don't name the function, but with the toggle= the Tests work \$\endgroup\$
    – user31373
    Commented May 20, 2016 at 13:57
  • \$\begingroup\$ yes, the toggle is needed to test it. But you only need to count from lambda m,t: on. \$\endgroup\$
    – Riker
    Commented May 20, 2016 at 14:04
  • \$\begingroup\$ You can change m+''+t to m+t to save 3 bytes, if I'm not mistaken. \$\endgroup\$
    – Sherlock9
    Commented May 20, 2016 at 14:37
  • \$\begingroup\$ 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 + \$\endgroup\$
    – user31373
    Commented May 20, 2016 at 14:38
2
\$\begingroup\$

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
\$\endgroup\$
2
\$\begingroup\$

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.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Also 11 bytes: ?}zQ:Qzk+Qz \$\endgroup\$
    – Blue
    Commented May 20, 2016 at 13:37
2
\$\begingroup\$

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(γ);
\$\endgroup\$
2
\$\begingroup\$

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

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

Racket, 70 bytes

Pretty straight forward.

(λ(s t)((if(string-contains? s t)string-replace string-append)s t""))
\$\endgroup\$
2
\$\begingroup\$

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

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

Oracle SQL 11.2, 66 bytes

SELECT DECODE(:1,s,s||:2,s)FROM(SELECT REPLACE(:1,:2)s FROM DUAL);
\$\endgroup\$
1
\$\begingroup\$

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

->u,v{u[v]?u.gsub(v,''):u+v}
\$\endgroup\$
1
\$\begingroup\$

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.

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

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.'
\$\endgroup\$
3
  • \$\begingroup\$ 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.) \$\endgroup\$
    – msh210
    Commented May 22, 2016 at 7:23
  • \$\begingroup\$ @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. \$\endgroup\$ Commented May 22, 2016 at 9:59
  • \$\begingroup\$ The order of input arguments is not fixed by the question afaict. \$\endgroup\$
    – msh210
    Commented May 22, 2016 at 14:50
1
\$\begingroup\$

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

\$\endgroup\$
3
  • \$\begingroup\$ 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? \$\endgroup\$ Commented May 22, 2016 at 19:50
  • \$\begingroup\$ 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 \$\endgroup\$
    – Blue0500
    Commented May 22, 2016 at 22:00
  • \$\begingroup\$ What about var F(string s, string t? That can be inferred... \$\endgroup\$ Commented Jul 7, 2016 at 1:00
1
\$\begingroup\$

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

\$\endgroup\$
1
  • \$\begingroup\$ This won't work if the toggle string contains special characters. \$\endgroup\$
    – Dennis
    Commented May 23, 2016 at 15:40
1
\$\begingroup\$

Julia, 33 31 bytes

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

Try it online!

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

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.

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

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

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

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.
\$\endgroup\$
0
\$\begingroup\$

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
\$\endgroup\$
1
  • \$\begingroup\$ Hello, and welcome to PPCG! Great answer! \$\endgroup\$ Commented May 20, 2016 at 16:10
0
\$\begingroup\$

TSQL(Sqlserver 2012), 49 bytes

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

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

Try it online!

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

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"
\$\endgroup\$
0
\$\begingroup\$

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
}
\$\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.