Toggle a string

15

1

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'

nobe4

Posted 2016-05-20T13:09:44.320

Reputation: 293

And once it goes to the main namespace, you guys ask all sorts of questions – Leaky Nun – 2016-05-20T13:17:43.350

2@KennyLau It was in the sandbox for all of 3 hours. The recommendation is 2 days. – Morgan Thrapp – 2016-05-20T13:18:32.757

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 – 2016-05-20T13:19:49.510

2So you replace all non-overlapping instances? – Suever – 2016-05-20T13:26:05.133

You can break quite a few solutions with the test-case: 'abc.', '.', since quite a lot of them use some sort of regex. – Jakube – 2016-05-20T15:48:47.193

1@Jakube Yes, I should limit this to letters and number I think. – nobe4 – 2016-05-20T16:20:18.990

1No, I think allow nonalphanumerics: it's more challenging that way. – msh210 – 2016-05-22T07:35:42.920

Is the order of the function parameters fixed (main_string as first and toggle_string as second parameter) or it is allowed to change the order? – Heiko Oberdiek – 2016-05-22T15:04:04.907

Yes, but you can propose your solution anyway, just for the challenge :) – nobe4 – 2016-05-22T15:05:13.657

Answers

5

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.

Dennis

Posted 2016-05-20T13:09:44.320

Reputation: 196 637

11

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`

Kevin Cruijssen

Posted 2016-05-20T13:09:44.320

Reputation: 67 575

1You 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 – 2016-05-20T13:33:17.797

@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 – 2016-05-20T13:38:14.040

1You can save a few more bytes by using a lambda instead of a regular function. – Denker – 2016-05-20T13:47:44.370

return m=m.replace(t,"")?m+t:m; – Leaky Nun – 2016-05-20T14:14:59.550

@KennyLau m=m.replace(t,"") isn't a boolean for the ternary if-operation.. :S And if you ment m==m.replace... instead, then the output is incorrect. – Kevin Cruijssen – 2016-05-20T14:33:54.963

2m==(m=m.replace... – Leaky Nun – 2016-05-20T14:34:58.293

@KennyLau Nice trick, thanks. I've edited the post. – Kevin Cruijssen – 2016-05-20T14:40:45.220

8

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

Suever

Posted 2016-05-20T13:09:44.320

Reputation: 10 257

6

Python 3, 38 bytes

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

Hunter VL

Posted 2016-05-20T13:09:44.320

Reputation: 321

4

JavaScript (ES6), 39 37 bytes

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

Neil

Posted 2016-05-20T13:09:44.320

Reputation: 95 035

3

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

Blue

Posted 2016-05-20T13:09:44.320

Reputation: 26 661

3

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)

aditsu quit because SE is EVIL

Posted 2016-05-20T13:09:44.320

Reputation: 22 326

19 bytes: q~:B/2Be]. – jimmy23013 – 2016-05-20T16:53:30.167

2

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.

Leaky Nun

Posted 2016-05-20T13:09:44.320

Reputation: 45 011

1Also 11 bytes: ?}zQ:Qzk+Qz – Blue – 2016-05-20T13:37:25.567

2

Javascript (ECMAScript 6): 47 bytes

(a,b)=>(c=a.replace(RegExp(b,'g'),''))!=a?c:a+b

nobe4

Posted 2016-05-20T13:09:44.320

Reputation: 293

5This can fail if the toggle string contains special characters. For example, ("a", ".") returns "" instead of "a.". – Dennis – 2016-05-20T15:23:03.740

2

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

Martin Ender

Posted 2016-05-20T13:09:44.320

Reputation: 184 808

2

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.

levanth

Posted 2016-05-20T13:09:44.320

Reputation: 405

Nice answer! For our rules, you don't need a name for the function. So you can remove the toggle=. – Rɪᴋᴇʀ – 2016-05-20T13:53:58.960

I just realized, my Test won't work if I don't name the function, but with the toggle= the Tests work – levanth – 2016-05-20T13:57:32.387

yes, the toggle is needed to test it. But you only need to count from lambda m,t: on. – Rɪᴋᴇʀ – 2016-05-20T14:04:10.097

You can change m+''+t to m+t to save 3 bytes, if I'm not mistaken. – Sherlock9 – 2016-05-20T14:37:06.520

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 – 2016-05-20T14:38:35.937

2

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

Avis

Posted 2016-05-20T13:09:44.320

Reputation: 21

1Welcome to Programming Puzzles & Code Golf! I don't know Scala, but I think you can remove the spaces around if(r==m). – Dennis – 2016-05-20T15:35:50.540

Yeah you are right – Avis – 2016-05-21T08:54:15.407

2

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

RedLaser

Posted 2016-05-20T13:09:44.320

Reputation: 131

2

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(γ);

Conor O'Brien

Posted 2016-05-20T13:09:44.320

Reputation: 36 228

2

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

MayorMonty

Posted 2016-05-20T13:09:44.320

Reputation: 778

2

Racket, 70 bytes

Pretty straight forward.

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

Winny

Posted 2016-05-20T13:09:44.320

Reputation: 1 120

1

Oracle SQL 11.2, 66 bytes

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

Jeto

Posted 2016-05-20T13:09:44.320

Reputation: 1 601

1

Julia, 33 31 bytes

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

Try it online!

Dennis

Posted 2016-05-20T13:09:44.320

Reputation: 196 637

1

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

Heiko Oberdiek

Posted 2016-05-20T13:09:44.320

Reputation: 3 841

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 – 2016-05-22T07:23:11.057

@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 – 2016-05-22T09:59:03.387

The order of input arguments is not fixed by the question afaict. – msh210 – 2016-05-22T14:50:38.720

1

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

Blue0500

Posted 2016-05-20T13:09:44.320

Reputation: 111

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 – 2016-05-22T19:50:58.143

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 – 2016-05-22T22:00:14.710

What about var F(string s, string t? That can be inferred... – NoOneIsHere – 2016-07-07T01:00:47.733

1

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

Thiht

Posted 2016-05-20T13:09:44.320

Reputation: 131

This won't work if the toggle string contains special characters. – Dennis – 2016-05-23T15:40:07.063

0

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.

AdmBorkBork

Posted 2016-05-20T13:09:44.320

Reputation: 41 581

0

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

nickb

Posted 2016-05-20T13:09:44.320

Reputation: 351

0

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.

Sherlock9

Posted 2016-05-20T13:09:44.320

Reputation: 11 664

This can fail if the toggle string contains special characters. For example, ("a", ".") returns "a" instead of "a.". – Dennis – 2016-05-20T15:21:37.453

m[t] is much shorter than m.include?(t) and still checks for inclusion within strings. – Value Ink – 2016-05-20T18:26:05.567

0

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

dfundako

Posted 2016-05-20T13:09:44.320

Reputation: 141

Hello, and welcome to PPCG! Great answer! – NoOneIsHere – 2016-05-20T16:10:17.987

0

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

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

Luis Masuelli

Posted 2016-05-20T13:09:44.320

Reputation: 141

0

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.

LegionMammal978

Posted 2016-05-20T13:09:44.320

Reputation: 15 731

0

TSQL(Sqlserver 2012), 49 bytes

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

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

Try it online!

t-clausen.dk

Posted 2016-05-20T13:09:44.320

Reputation: 2 874

0

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"

skeevey

Posted 2016-05-20T13:09:44.320

Reputation: 4 139

0

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
}

The_Lone_Devil

Posted 2016-05-20T13:09:44.320

Reputation: 191

0

Rust, 84 bytes

fn toggle(a:&str,b:&str)->String{let mut r=a.replace(b,"");if&r==a{r.push_str(b)}r}

Try it on play.rust-lang.org.

pgy

Posted 2016-05-20T13:09:44.320

Reputation: 830

0

PHP 65

function f($s,$v){return($m=str_replace($v,'',$s))==$s?$s.$v:$m;}

Inspired from Kevin Cruijssen's java example.

kuldeep.kamboj

Posted 2016-05-20T13:09:44.320

Reputation: 625

0

PHP, 73 chars

<?$s=$argv[1];$t=$argv[2];echo!strpos($s,$t)?$s.$t:str_replace($t,'',$s);

Longer than the other php answer, but uninspired and fully working as a standalone in the console.

timmyRS

Posted 2016-05-20T13:09:44.320

Reputation: 329