# String subtraction

## Objective

Create a function to reverse string concatenation

## Input

Two strings (alphanumeric + spaces), where one should be subtracted for the other.

• You can assume that the string to be subtracted will never be larger than the other one.

## Output

The result from the subtraction

## Subtraction

You should remove one string from the start or the end of another string. If the string is present in the start and in the end, you can only remove one, which one will be removed is up to you.
If the string isn't in the start or in the end, or isn't an exact match, it is an invalid subtraction and you should output the original string.

## Test Cases

### Valid Subtraction

'abcde','ab' -> 'cde'
'abcde','cde' -> 'ab'
'abab','ab' -> 'ab'
'abcab','ab' -> 'abc' or 'cab'
'ababcde','ab' -> 'abcde'
'acdbcd','cd' -> 'acdb'
'abcde','abcde' -> ''
'abcde','' -> 'abcde'
'','' -> ''


### Invalid Subtraction (returns original string)

'abcde','ae' -> 'abcde'
'abcde','aa' -> 'abcde'
'abcde','bcd' -> 'abcde'
'abcde','xab' -> 'abcde'
'abcde','yde' -> 'abcde'


### Invalid Input (don't need to be handled)

'','a' -> ''


This is , so the shortest code in bytes wins!

• Why is the result of the first case not cde? What do you mean by valid? Do we need to judge the validity of the input, or do you mean that we will not receive invalid inputs? May 16 '17 at 16:01
• Damn you, 'abcde','bcd' -> 'abcde', for breaking my solution May 16 '17 at 16:26
• Can we assume the strings will be regex-safe (alphanumeric + spaces)? May 16 '17 at 16:27
• I'd suggest 'ababcde', 'ab''abcde' as a test case. Some naive algorithms fail on that one.
– user62131
May 16 '17 at 16:48
• @Rod You might consider retitling the challenge "Reverse string concatenation"? May 16 '17 at 19:52

# Java 8, 464544 40 bytes

-1 byte thanks to TheLethalCoder

-1 byte because I'm dumb (thanks Rod!)

-4 bytes thanks to Kevin Cruijssen

a->b->a.replaceFirst("^"+b+"|"+b+"$","")  Try it online! (includes all test cases) A Java answer actually beats a few other practical languages. Smiles. (and now it beats JS!) • Use currying to save a byte a->b-> May 16 '17 at 17:08 • @TheLethalCoder Thanks. – Okx May 16 '17 at 17:28 • Why did you leave in the unused hashmap in your online example? May 17 '17 at 12:52 • You can change the First to All for -2 bytes. Because of the ^ and $ it's always either at the end or start of the String, so even with replaceAll it only replaces it once. Try it here. PS: I added the previous byte-counts striked-through to your answer, which is what usually is done after code-golf edits here on PPCG. May 18 '17 at 9:00
• @KevinCruijssen I knew about the strike-throughs, guess I just forgot this time. However, if i use All instead of First, this becomes true: "abab" + "ab" -> ""
– Okx
May 18 '17 at 9:43

# Brachylog (Try It Online!), 12 bytes

~cpĊh.∧Ċtw|w


Try it online!

Takes the string to subtract from from standard input, and the string to subtract as a command line argument.

## Explanation

~cpĊh.∧Ċtw|w
~c            Split {the input} into pieces
p           and (possibly) rearrange those pieces
Ċ          such that there are two pieces
h         and the first
.        matches the command line argument
∧       then
w    print
t     the last
Ċ      piece.
|   If all else fails,
w  print {the input}.


$3  Try it online! # JavaScript (ES6), 767045 41 bytes s=>t=>s.replace(RegExp(^${t}|${t}$),"")


## Try It

f=
s=>t=>s.replace(RegExp(^${t}|${t}$),"") o.innerText=f(i.value="abcde")(j.value="ab") i.oninput=j.oninput=_=>o.innerText=f(i.value)(j.value) <input id=i><input id=j><pre id=o> • You don't need new . – user58826 May 16 '17 at 18:11 • @programmer500, I kinda gave up working on this when I saw ETH's version! :D Updated now. Thanks. May 16 '17 at 18:17 # Perl 6, 21 bytes ->$_,$b {S/^$b|$b$//}


Try it

## Expanded:

-> $_,$b {   # pointy block lambda

S/          # Str replace and return (implicitly against ｢$_｣) | ^$b    # starting with the second argument
|     $b$  # or ending with the second argument

//          # replace with nothing.

}


# Japt, 11 9 bytes

k"^|$"¬qV  Try it online! # TI-Basic (TI-84 Plus CE), 63 bytes Prompt Str0,Str2 inString(Str0,Str2 If Ans sub(Str0,1,Ans-1)+sub(Str0,Ans+length(Str2),length(Str0)-Ans+1-length(Str2→Str0 Str0  • I have a question, why didn't you use Str1 as a variable? Aug 9 '17 at 20:57 • @Zacharý I think I had something stored in it at the time. I don't really remember. Aug 9 '17 at 21:02 • What does Ans even refer to on the fourth line? Aug 9 '17 at 21:30 • @Zacharý Ans refers to the last evaluated value, so in this case it refers to the value returned by inString(, which is the index of the substring Str2 in the string Str0 or 0 if the substring does not appear. An if statement does not modify the value of Ans, so on the fourth line the index is still in Ans. Aug 9 '17 at 21:34 • Oh, I forgot how inString worked. Nice golf! Aug 9 '17 at 21:42 ## Mathematica, 162 bytes (c=Characters;a=c@#;b=c@#2;l=Length;t={};If[l@Intersection[a,b]==l@b,If[MemberQ[Partition[a,l@b,1],b],t=a;Table[t=DeleteCases[t,b[[i]],1,1],{i,l@b}]],t=a];""<>t)&  test input style ["abcde","ab"] • Nice solution! You can save a byte by using # instead of #1 — they mean exactly the same. Also, instead of using StringJoin@t, you can cheat by joining an empty string to it with ""<>t, which automatically joins everything in t together too. Have you seen the Mathematica golfing tips page? May 17 '17 at 0:50 • There are a few more things you can do to save bytes (I don't think you don't need to define t={}; at the start, for instance), but it might be easier to use a different approach entirely — have you tried using the StringReplace function? May 17 '17 at 1:13 • You are allowed to take a String array as input, so you don't really need c=Characters;a=c@#;b=c@#2; May 17 '17 at 5:55 • Also, l@Intersection[a,b] is l[a∩b]. May 17 '17 at 5:56 # Python, 6968645751 45 bytes This ended up being a completely different solution with Regex. Thanks to Value Ink for -2 bytes! and Felipe Nardi Batista for the massive -6 bytes! import re lambda s,c:re.sub(c+'$|^'+c,'',s,1)


Try it online!

• For -2 bytes: re.sub(c.join("^|$"),'',s,1) May 17 '17 at 0:33 • For -6 bytes:c+'$|^'+c May 18 '17 at 0:02

# Bash, 6661 49 bytes

case $1 in *$2)echo ${1%$2};;*)echo ${1#$2};;esac


Try it online!

less golfed:

a=$1; case$1 in
*$2) c=${a%$2};;$2*)  c=${a#$2};;
*)  c=$1;; esac; echo$c


Uses case to test begining or end, and array prefix/suffix (% / #) substraction

• Nice use of case, but longer than necessary. The 2nd and 3rd pattern could be merged into a single one: *)c=${1#$2};;. Then with only 2 branches would be shorter to echo each directly instead of using variable $c: case$1 in *$2)echo${1%$2};;*)echo${1#$2};;esac. Or you could keep using it, but without case: c=${1%$2};[[$c = $1 ]]&&c=${1#$2};echo$c. May 18 '17 at 7:47

# APL (Dyalog), 31 30 bytes

-1 thanks to Zacharý.

This actually uses reverse (i.e. the inverse of) concatenation! Takes original string as left argument, and what to subtract as right argument.

{0::⍺{0::⍺⋄,∘⍵⍣¯1⊢⍺}⍵⋄⍵,⍣¯1⊢⍺}


Try it online!

Ungolfed:

{
0::⍺{         ⍝ if an error happens, apply the following function on the arguments
0::⍺          ⍝ if an error happens, return the left argument unmodified
,∘⍵⍣¯1⊢⍺      ⍝ inverse-append right argument on left argument
}⍵
⍵,⍣¯1⊢⍺      ⍝ inverse-prepend the right argument on the left argument
}


Legend:

{} anonymous function

⍺ left argument of the current function

⍵ right argument of the current function

0::… if any error happens, execute this, else…

⍣¯1⊢ inverse

,∘⍵ concatenate on the right

⍵, concatenate on the left

• I think you can save a byte with {0::⍺{0::⍺⋄,∘⍵⍣¯1⊢⍺}⍵⋄⍵,⍣¯1⊢⍺}. Aug 9 '17 at 20:56
• @Zacharý Yes, thanks.
Aug 9 '17 at 21:22

# PHP, 54 Bytes

[,$x,$y]=$argv;echo preg_replace("#^$y|$y$#","",$x,1);  Testcases # Python 2, 68 bytes def f(s,c):v=len(c);print[s[v:],s[:-v],s][[s[:v],s[-v:],c].index(c)]  Try it online! # Haskell, 49 bytes f s a b|s==b=a|a/=b,h:t<-a=f(s++[h])t b|1<3=s f""  Try it online! Usage: f"" "abcdef" "ab". Alternatively, define (-)=f""and use like "abcdef" - "ab". This regex-free solution works by recursively splitting the string in all its pre- and postfixes and checking whether the string to be substracted matches one of them. # Python 2, 72 65 bytes a,b=input() l=len(b) print[[a,a[:-l]][b==a[-l:]],a[l:]][b==a[:l]]  Try it online! -7 bytes thanks to @FelipeNardiBatista • golfed May 17 '17 at 23:33 • @FelipeNardiBatista thanks a lot! – ovs May 18 '17 at 4:26 # C#, 88 bytes s=>r=>s.StartsWith(r)?s.Substring(r.Length):s.EndsWith(r)?s.Substring(0,s.IndexOf(r)):s;  Compiles to a Func<string, Func<string, string>>. ### Ruby (lambda expression), 29 bytes ->a,b{a.sub /^#{b}|#{b}$/,""}


Yay for regex interpolation! Requires regex-safe subtrahends, but that's okay as per the challenge.

# Tcl, 37 bytes

proc s {a b} {regsub "^$b|$b$"$a {}}


Try it online! (now running all tests)

Tcl is straightforward. proc s {a b} defines a function named s which takes parameters a and b. regsub substitutes {}, which is an empty string, for the value of b when it's at the start or end of a. The return is implicit.

# C, 96 bytes

It's common knowledge that string manipulation in C is cumbersome, as an extension golfing would be borderline masochistic. Sounds alright to me.

f(a,b,t,l)char**a,*b,*t;{t=*a;l=strlen(b);bcmp(t,b,l)?bcmp(t+=strlen(t)-l,b,l)||(*t=0):(*a+=l);}


One of the less readable programs I've written. Takes two inputs (despite how the function looks), a char** pointing to the string to deconcatenate and a char* which is the string to remove. The input pointer is edited in place and becomes the output (who cases about memory leaks anyway).

Example usage:

char *a = malloc(6);
strcpy(a, "abcde");
char *b = malloc(4);
strcpy(b, "abc");
f(&a,b);
printf("%s\n", a); // "de"


# AWK, 21 32 bytes

{sub("^"$2"|"$2"$",z,$1);$0=$1}1


Try it online!

Original submission naively replaced text within first string, not just at beginning or end.

{sub($2,z,$1);$0=$1}1


Try it online !

Originally tried without the braces, but it required tricks to print out empty lines and or no-matches which ended up adding more bytes than this version.

# R, 2042 41 bytes

pryr::f(sub(sprintf('^%s|%s$',b,b),'',a))  -1 byte thanks to MickyT! Returns an anonymous function (which has arguments in the order b,a). Computes the string difference a-b. sub is a simple substitution that swaps the first occurrence of the pattern with, in this case, the empty string ''. Constructs the regex with sprintf to match only at the beginning and end of string. Requires the pryr package to be installed. On the TIO link, uses the more verbose function(a,b) definition for the function for four more bytes. Try it online! • What about the 'abcde','bcd' -> 'abcde' case? May 16 '17 at 16:18 • "sub is a simple substitution that simply swaps the first occurrence of b in a": Will this swap if the second string is in the middle of the first string? May 16 '17 at 16:18 • I misread the question! Oops. Thanks for catching that! May 16 '17 at 16:31 • you can get 1 byte back with sprintf('^%s|%s$',b,b) May 17 '17 at 22:36
• @MickyT, thanks! fixed. May 18 '17 at 19:02

# Common Lisp, 121 bytes

(lambda(x y)(cond((equal(#1=subseq x 0 #3=(length y))y)(#1#x #3#))((equal(#1#x #2=(-(length x)#3#))y)(#1#x 0 #2#))(t x)))


Try it online!

The usual wordy Common Lisp!

Ungolfed version:

(defun f(x y)
(cond ((equal (subseq x 0 (length y)) y)               ; if x starts with y
(subseq x (length y)))                          ; return rest of x
((equal (subseq x (- (length x) (length y))) y)  ; if x ends with x
(subseq x 0 (- (length x) (length y))))         ; return first part of x
(t x)))                                          ; else return x


# Kotlin, 91 bytes

{a,b->val v=b.length
if(a.startsWith(b))a.drop(v)else if(a.endsWith(b))a.dropLast(v)else a}


Try it online!

• ? {a,b->var c=a.removePrefix(b);if(a==c){c=a.removeSuffix(b)};c} Oct 2 '18 at 8:33
• @mazzy feel free to submit that as your own answer. Oct 2 '18 at 18:01

# Powershell, 34 40 bytes

+6 bytes when Invalid Subtraction test cases added

param($s,$t)$s-replace"^$t(?!.*$t$)|$t$"


Comment:

The regexp expression ^$t|$t$ does not work as expected: it replaces both matches instead one (flag g always on). So, we are forced to use the negative lookahead group. Test script: $f = {
param($s,$t)$s-replace"^$t(?!.*$t$)|$t$"
}

@(
,('abcde','ab', 'cde')
,('abcde','cde', 'ab')
,('abab','ab', 'ab')
,('abcab','ab', 'abc', 'cab')
,('ababcde','ab', 'abcde')
,('acdbcd','cd', 'acdb')
,('abcde','abcde', '')
,('abcde','', 'abcde')
,('','', '')

,('abcde','ae', 'abcde')
,('abcde','aa', 'abcde')
,('abcde','bcd', 'abcde')
,('abcde','xab', 'abcde')
,('abcde','yde', 'abcde')

,('','a', '')
) | % {
$s,$t,$e =$_
$r = &$f $s$t
"$($r-in$e):$r"
}


Output:

True: cde
True: ab
True: ab
True: abc
True: abcde
True: acdb
True:
True: abcde
True:


## QBIC, 57 bytes

Whegh, this is a mess in QBIC/QBasic...

B=@ +B┘x=instr(;,;)~x|?_t_sB,x-1|+_sB,x+_lC|,_lB|||\?B

B=@ +B          Prepend a string to B$. Thisis a hack to avoid errors with removing substrings stating at index 1 ┘ Line-break in QBasic output (;,;) Read the string (B$) and the to-be-removed substring (C$) x=instr And make x to be the starting index of the first C$ in B$~x| IF X <> 0 (ie C$ is present in B$) ? PRINT _t trimmed version (drops the prepended space) _sB,x-1|+ of a substring from 1 to x (the start of C$) -1
_sB,x+_lC|,_lB   and the rest of the string, starting after C$_l takes the length of a string ||| End TRIM, end Substring, end Length \?B When missing C$, just print B$ # Lua, 71 65 bytes Accepting suggestions a,b=...p='(.*)'print(a:match('^'..b..p)or a:match(p..b..'$')or a)


Try it online!

I initially misread the instructions. Thanks, Ørjan Johansen for pointing out my mistake!

# PowerShell, 46 51 bytes

Function F($o,$a){([regex]"^$a").replace($o,'',1);}


Try it online!

• This fails on the 'abcde' 'bcd' case. May 17 '17 at 23:11
• I'm seeing expected results from that test case -- TIO here May 18 '17 at 14:25
• It's a listed test case of the OP and the result should be abcde - bcd does not occur at either end of the string. May 18 '17 at 17:13
• You are correct. I misread the instructions. Thanks for pointing it out! May 18 '17 at 17:49

# Excel, 129 bytes

=IFERROR(IF(FIND(B1,A1)=1,SUBSTITUTE(A1,B1,"",1),IF(FIND(B1,A1,LEN(A1)-LEN(B1))>LEN(A1)-LEN(B1),LEFT(A1,LEN(A1)-LEN(B1)),A1)),A1)


# sed, 56 53 bytes

s/^(.*),(.*)\1$/\2/ s/^(.*),\1(.*)$/\2/
s/.*,(.*)/\1/


Try it online!