Longest Common Prefix of 2 Strings

Write a program that takes 2 strings as input, and returns the longest common prefix. This is , so the answer with the shortest amount of bytes wins.

Test Case 1:

"global" , "glossary"
"glo"

Test Case 2:

"department" , "depart"
"depart"

Test Case 3:

"glove", "dove"
""

• Another good test case is "aca", "aba". – Morgan Thrapp Nov 3 '15 at 19:00
• Do you want a complete programs that inputs from STDIN and prints to STDOUT, or are functions OK? – xnor Nov 3 '15 at 19:35
• Can we assume the input won't have newlines? Which characters will the input have? – Downgoat Nov 3 '15 at 23:59
• General note: People using a regex based solution should not copy other people's regex answers without testing them yourself; this does not work in all regex engines. In particular, it gives different (both incorrect) answers in nvi and vim. – Random832 Nov 4 '15 at 16:38
• All of the examples given are in lowercase, but do we need to worry about case sensitivity? For example, should global and GLOSSARY return glo or ''? – AdmBorkBork Nov 5 '15 at 16:08

Python 3, 54 bytes

Thanks Python for having a built-in function for this task! :D

import os;print(os.path.commonprefix(input().split()))


Takes input as two words separated by a space such as glossary global.

(c:x)%(d:y)|c==d=c:x%y;_%_=""


Usage:

>> "global"%"glossary"
"glo"


Recursively defines the binary function % by pattern matching. On two strings with equal first letters, takes that first letters, and prepends it to the function of the remainder of the strings. On anything else, gives the empty string.

Pyth, 8 7 bytes

e@F._MQ


Thanks @isaacg for 1 byte off

Takes input quoted and comma separated, like "abc", "acc". This exits on an error (but leaves stdout empty) when the result is the empty string. If that is unacceptable, add 2 bytes for #e@F._MQq

Test Suite

Explanation

e@F._MQ        : implicit Q = eval(input)
._MQ        : Map the prefix operator onto both inputs
@F            : Fold the setwise intersection operator over those lists
e              : Take the last such element, the prefixes are always made from shortest
: to longest, so this always gives the longest matching prefix

• To make the result the empty string without error: e|@F._M.z]k. – kirbyfan64sos Nov 3 '15 at 18:11
• @kirbyfan64sos I believe the thing I put in about surrounding it with #...q is one byte less than that, I'll edit in the full code, I guess that is confusing – FryAmTheEggman Nov 3 '15 at 18:14
• Take input in the form "abc", "def" and you can use Q instead of .z – isaacg Nov 3 '15 at 22:55

C++, 101100 99 bytes

#include<iostream>
int i;main(){std::string s,t;std::cin>>s>>t;for(;s[i]==t[i];std::cout<<s[i++]);}


Reads two strings from stdin, prints the character at the current position from one of the strings while the character at the current position is equal to the character at the same position in the other string.

Thanks to Zereges for saving one byte.

• That is a beautiful and terrifying use of the for statement... – Joshpbarron Nov 4 '15 at 13:28
• The loop would fail to terminate if the strings were equal. – Jon Trauntvein Nov 5 '15 at 23:00
• Won't work for strings containing whitespaces. You can save one byte, by making int i in global space (so that it will be 0 initialized) – Zereges Nov 5 '15 at 23:01
• @JonTrauntvein I think that case is UB(?). It works™ for me though. (gcc-5.1) – sweerpotato Nov 10 '15 at 17:29

((map fst.fst.span(uncurry(==))).).zip


Usage example: ( ((map fst.fst.span(uncurry(==))).).zip ) "global" "glossary" -> "glo".

Zip both input string into a list of pairs of characters. Make two lists out of it: the first one with all pairs from the beginning as long as both characters are equal, the second one with all the rests. Drop the second list and extract all characters from the first list.

CJam, 1211 9 bytes

l_q.-{}#<


This reads the strings on two separate lines with Unix-style line ending, i.e., <string>\n<string>\n.

Thanks to @MartinBüttner for -1 byte, and to @jimmy23013 for -2 bytes!

Try it online in the CJam interpreter.

How it works

l_         e# Read a line (w/o trailing LF) from STDIN and push a copy.
q        e# Read another line from STDIN (with trailing LF).
e# The trailing linefeed makes sure that the lines are not equal.
.-      e# Perform vectorized character subtraction. This yields 0 for equal
e# characters, a non-zero value for two different characters, and the
e# characters themselves (truthy) for the tail of the longer string.
{}#   e# Find the index of the first truthy element.
<  e# Keep that many characters from the first string.

• Darn, I can't believe my very first answer was so close! – geokavel Nov 4 '15 at 16:46
• You can cheat a bit by assuming a trailing newline and use l_q.-. – jimmy23013 Nov 5 '15 at 2:18
• @jimmy23013 That's standard for input on Unix-like OS's, so why not? Thanks! – Dennis Nov 5 '15 at 2:28

APL, 13

{⊃↓K/⍨=⌿K←↑⍵}


This is a function that takes an array of two strings, and returns the prefix:

      {⊃↓K/⍨=⌿K←↑⍵}'glossary' 'global'
glo
{⊃↓K/⍨=⌿K←↑⍵}'department' 'depart'
depart

• Is it really fair to say that the APL alphabet is an alphabet of byte-size characters? Or is that standard practice around here? – Filipq Nov 3 '15 at 23:43
• @Filipq Answers here use the encoding most natural to the language. APL has its own code page on which each character is a single byte. – Alex A. Nov 4 '15 at 3:40

AppleScript, 215 Bytes

And I tried so hard... ;(

set x to(display dialog""default answer"")'s text returned
set a to(display dialog""default answer"")'s text returned
set n to 1
set o to""
repeat while x's item n=a's item n
set o to o&x's item n
set n to n+1
end
o

I wanted to see how well AppleScript could pull this off, and man is it not built for string comparisons.

• AppleScript wasn't built for anything. – kirbyfan64sos Nov 3 '15 at 23:51
• The only thing I use it for besides terrible golfs is tell app "System Events" to <something>. It is interesting to see how it deals with this kind of stuff, though. @kirbyfan64sos – Addison Crump Nov 4 '15 at 14:30

rs, 14 bytes

(.*).* \1.*/\1


Live demo and test cases.

This is pretty simple. It just matches the...longest common prefix and removes the rest of the string. If there is no longest common prefix, it just clears everything.

sed, 18

I had something much longer and more complicated in mind, so credit for this idea goes to @kirbyfan64sos.

s/(.*).* \1.*/\1/


Includes +1 for the -r option to sed.

• What was your original idea? – kirbyfan64sos Nov 3 '15 at 23:51
• @kirbyfan64sos It basically involved looping through characters one by one and stopping at a mismatch. It was just an idea - no code behind it. – Digital Trauma Nov 3 '15 at 23:54

CJam, 128 26

r:AAr:B.=0#_W={;;ABe<}{<}?


Try it Online.

(Got idea to use .= instead of .- after looking at Dennis's answer.)

With all the edge cases, it became to hard for a CJam beginner like me to keep it short. Hopefully, this at least works for all cases.

C#, 201 147 bytes

using System.Linq;class a{static void Main(string[]a){a[0].Take(a[1].Length).TakeWhile((t,i)=>a[1][i]==t).ToList().ForEach(System.Console.Write);}}


I know it isn't terribly competitive. I just wanted to see what it would look like.

EDIT: Thanks Ash Burlakzenko, Berend, and Dennis_E

• Just getting a C# answer under 250 bytes is competitive. Also, can't you just using System.*? – clap Nov 3 '15 at 22:45
• .ForEach(x=>Console.Write(x)) could be shortened to .ForEach(Console.Write) – Ash Burlaczenko Nov 4 '15 at 8:01
• using System.Collections.Generic; is unnecessary. Shave off one more byte by removing the space from string[] a. – Berend Nov 4 '15 at 9:16
• 1-The Contains is unnecessary. 2-You can save a few bytes by removing using System; and saying System.Console.Write; 3-This code returns the wrong result ("a") for input "aab","aaab", because of IndexOf. The shortest fix I could think of is using a[0].Take(a[1].Length) This is 147 bytes long: "using System.Linq;class a{static void Main(string[]a){a[0].Take(a[1].Length).TakeWhile((c,i)=>a[1][i]==c).ToList().ForEach(System.Console.Write);}}" – Dennis_E Nov 4 '15 at 12:36
• Thanks for the comments when I get a break I'll take a good look at all of them especially Dennis_E's comment. – Jakotheshadows Nov 4 '15 at 17:46

Common Lisp, 39

(lambda(a b)(subseq a 0(mismatch a b)))


Takes two string arguments, determines the index i where they differ, and returns a substring from 0 to i.

Perl 5, 2019 18 bytes

19 bytes, plus 1 for the -E flag instead of -e:

say<>=~/^(.*).* \1/


This is copied shamelessly from Digital Trauma's sed answer. It assumes the input is a couple of words without spaces in them (or before the first) and with one space between them.

Update:

ThisSuitIsBlackNot suggested using -pe as follows, to save a byte (thanks!):

($_)=/^(.*).* \1/  And then Luk Storms suggested using -nE as follows to save another byte (thanks!): say/^(.*).* \1/  (I'm counting -E as one byte instead of the standard -e, but -n or -p as two. My impression is that that's SOP around here.) Python 3, 72 31 bytes saved thanks to FryAmTheEggman. 8 saved thanks to DSM. r='' for x,y in zip(input(),input()): if x==y:r+=x else:break print(r)  • What would Python programmers do without zip? :D – Beta Decay Nov 3 '15 at 20:58 • @BetaDecay Our fly would be open all the time. – Morgan Thrapp Nov 3 '15 at 21:00 • You could put the input()s in the zip and save the a and b binding. – DSM Nov 9 '15 at 22:06 • @DSM Ooo, good point. Thanks! – Morgan Thrapp Nov 9 '15 at 22:07 Python 3, 47 def f(w):[print(end=c[c!=d])for c,d in zip(*w)]  A function that takes a list w of two words, and prints the common prefix before terminating with an error. Python 3's print function lets you prints strings flush against each other with print(end=c) (thanks to Sp3000 for saving 3 bytes with this shorter syntax). This repeatedly take two letters from the words, and prints the first of the letters. The indexing c[c!=d] gives an out-of-bounds error where c!=d, terminating the execution when two unequal letters are encountered. An explicit for loop is one char longer than the list comprehension: def f(w): for c,d in zip(*w):print(end=c[c!=d])  • Wow! I hadn't even thought about using a function! Nice one. +1 – Zach Gates Nov 4 '15 at 21:32 • Only saw this now, but how about print(end=c[c!=d])? – Sp3000 Nov 10 '15 at 6:11 • @Sp3000 Wow, I never connected that the main argument to print being optional meant it could be called with only the end argument, and that could contain the string. That's a really useful trick in general. You should make a tip. – xnor Nov 10 '15 at 7:49 Javascript ES6, 52 bytes f=(a,b)=>[...a].filter((e,i)=>e==b[i]?1:b='').join  Usage: >> f("global","glossary") "glo"  • Does not work with ada,aca... – flawr Nov 3 '15 at 22:07 • Whoops, fixed. Forgot to kill filtering after the strings no longer match. – Dendrobium Nov 3 '15 at 22:17 • You don't need to name the function, so you can leave out the f= – Ypnypn Nov 3 '15 at 22:56 • you can do it smaller with map (a,b)=>[...a].map((e,i)=>e==b[i]?e:b='').join – Shaun H May 16 '16 at 17:44 Retina, 14 bytes Uses the same idea as kirbyfan64sos. Unfortunately, despite Martin's claim that eventually Match mode will feature a way to print capturing groups, it hasn't been implemented yet. Otherwise, (.*).* \1 could be used along with 2 bytes or so for some not-yet-existing configuration string option. (.*).* \1.*$1


Each line would go in its own file, with 1 byte added per additional file. Alternatively, run in a single file with the -s flag.

• The equivalent regex fails to match in vim due to greediness (and a non-greedy regex will match the shortest substring, i.e. blank), are you sure it works? – Random832 Nov 4 '15 at 16:31
• @Random832 Try using this regex replace tester, with the .NET option checked. Set the operation to "replace", and put the patterns in the correct boxes. It doesn't fail to match if there should be one. How could it possible fail due to greediness? That's the only reason it works. \1 ensures that both words start with the same prefix. So no matter how greedy (.*) is, \1 is the same. – mbomb007 Nov 4 '15 at 16:39
• In vim it refuses to match at all - I think it is finding a longer string for the first (.*), then failing to match it against \1, then not properly backtracking to shorter strings. – Random832 Nov 4 '15 at 16:40
• @Random832 Then you need to find something else to test your regexes on. – mbomb007 Nov 4 '15 at 16:41

K, 24 bytes

{(+/&\=/(&/#:'x)#'x)#*x}


Find the minimum of the length of each string. ((&/#:'x)). Trim each string to that length (#'x). Then compare, smear and sum the resulting sequence:

  =/("globaa";"glossa")
1 1 1 0 0 1
&\=/("globaa";"glossa")
1 1 1 0 0 0
+/&\=/("globaa";"glossa")
3


Finally, take that many characters from the first of the strings provided (#*x).

In action:

 f: {(+/&\=/(&/#:'x)#'x)#*x};
f'(("global";"glossary")
("department";"depart")
("glove";"dove")
("aaa";"aaaaa")
("identical";"identical")
("aca";"aba"))
("glo"
"depart"
()
"aaa"
"identical"
,"a")


Powershell, 65 bytes

Compare the strings, shrinking the first until it either matches (print and exit) or the string is null and the loop terminates.

param($a,$b)while($a){if($b-like"$a*"){$a;exit}$a=$a-replace".$"}  Julia, 62 bytes f(a,b)=(c="";for(i,j)=zip(a,b) i!=j?break:(c*=string(i))end;c)  Ungolfed: function f(a::AbstractString, b::AbstractString) # Initialize an output string c = "" # Iterate over the pairs of characters in a and b, # truncated to the shorter of the two lengths for (i, j) in zip(a, b) if i == j # If they match, append to the output string c *= string(i) else # Otherwise stop everything! break end end return c end  Fixed an issue (at the hefty cost of 14 bytes) thanks to xnor! C99, 73 bytes main(int c,char *a[]){for(char *x=a[1],*y=a[2];*x==*y++;putchar(*x++));}  Similar to this answer, but shorter and meets spec (takes input from stdin). • Spec doesn't say input has to come from stdin. This is actually longer than the other answer if you add #include<stdio.h>, which is necessary for the program to compile. – musarithmia Dec 18 '15 at 19:18 • @AndrewCashner - It doesn't need to be on stdin, but it does need to take input. The other answer is hard-coded. Also, gcc whines about the implicit usage, but it compiles fine without the include. – Comintern Dec 18 '15 at 19:23 • Much shorter without the temporaries: main(int c,char**a){for(;*a[1]==*a[2]++;putchar(*a[1]++));} (59 bytes). – Toby Speight Jul 4 '18 at 12:10 MATLAB, 50 40 bytes Defines a function that accepts 2 strings as input, outputs to command window function t(a,b);a(1:find([diff(char(a,b)) 1],1)-1)  This solution will work for any string, outputs ans = Empty string: 1-by-0  if no match is given. Can be golfed by using a script instead of a function (using local variables a, b) (-16 bytes). so getting 34 Bytes a(1:find([diff(char(a,b)) 1],1)-1)  The function style (which seems to be the accepted style), yields @(a,b)a(1:find([diff(char(a,b)) 1],1)-1)  (Thanks @Stewie Griffin) • 40 bytes: @(a,b)a(1:find([diff(char(a,b)) 1],1)-1). =) – Stewie Griffin Nov 27 '15 at 10:54 Perl 6, 28 bytes I came up with two that take their values from STDIN which are based on the Perl 5 answer. lines~~/(.*).*' '$0/;say ~$0  lines~~/:s(.*).*$0/;say ~$0  The first requires exactly one space between the inputs, while the other requires at least one whitespace character between the inputs. That is quite a bit shorter than the first thing I tried which takes the values from the command line. say [~] map ->($a,$b){$a eq$b&&$a||last},[Z] @*ARGS».comb # 58 bytes


or even the lambda version of it:

{[~] map ->($a,$b){$a eq$b&&$a||last},[Z] @_».comb} # 52 bytes  Though this is much easier to adjust so that it accepts any number of input strings, at the cost of only one stroke. {[~] map ->@b {([eq] @b)&&@b[0]||last},[Z] @_».comb} # 53 bytes # ┗━┛ ┗━━━━━━━┛ ┗━━━┛  my &common-prefix = {[~] map ->@b {([eq] @b)&&@b[0]||last},[Z] @_».comb} say common-prefix <department depart>; # "depart" say common-prefix; # "" say common-prefix <department depart depot deprecated dependant>; # "dep" # This code does not work directly with a single argument, so you have # to give it an itemized List or Array, containing a single element. say common-prefix$('department',); # "department"

# another option would be to replace @_ with (@_,)


Japt, 27 bytes

Japt is a shortened version of JavaScript. Interpreter

Um$(X,Y)=>$A&&X==VgY ?X:A=P


(The strings go into the Input box like so: "global" "glossary")

This code is exactly equivalent to the following JS:

A=10;(U,V)=>U.split.map((X,Y)=>A&&X==V[Y]?X:A="").join


I have not yet implemented anonymous functions, which is what the $...$ is for: anything between the dollar signs is left untouched in the switch to JS. After I add functions, this 21-byte code will suffice:

UmXY{A&&X==VgY ?X:A=P


And after I implement a few more features, it will ideally be 18 bytes:

UmXY{AxX=VgY ?X:AP


Suggestions welcome!

So it turns out that this program is only 15 bytes in modern Japt:

¡A©X¥VgY ?X:A=P


Try it online!

MATL, 11 9 bytes

y!=XdYpf)


Try it online!

(-2 bytes thanks to Giuseppe)

 y  % implicitly input the two strings, then duplicate the
%  first one into the stack again
%  stack: ['department' 'deported' 'department']
!  % transpose the last string into a column vector
=  % broadcast equality check - gives back a matrix comparing
%  every letter in first input with the letters in the second
Xd % diagonal of the matrix - comparison result of each letter with
%  only corresponding letter in the other string
%  stack: ['department' [1; 1; 1; 0; 1; 1; 0; 0;]]
Yp % cumulative product (so only initial sequence of 1s remains
%  1s, others become 0)
%  stack: ['department' [1; 1; 1; 0; 0; 0; 0; 0;]]
f  %  find the indices of the 1s
)  % index at those elements so we get those letters out
% (implicit) convert to string and display

• Thanks! The y idea is pretty good, I'd tried things like an initial iti instead of the 1Gw, but didn't think of using the y for that. – sundar - Reinstate Monica Jul 6 '18 at 13:24

Clojure/ClojureScript, 51

(defn f[[a & b][c & d]](if(= a c)(str a(f b d))""))


Pretty straightforward. Unfortunately the spaces around the parameter destructuring are necessary (that's the [a & b] stuff). Not the shortest but I beat some other answers in languages that like to brag about their terseness so I'll post it.

Python 2, 50 bytes

for a,b in zip(*input()):print(1/0if a!=b else a),


Input

The input is taken as two strings:

"global", "glossary"


Output

The output is each character followed by a space; which, hopefully, isn't a problem. However, if it is, I'll edit my answer.

g l o

• I'm pretty sure this is invalid; the spec clearly gave the output format as a string without spaces. – lirtosiast Nov 4 '15 at 1:15
• Well yes, but the input was also given in the format "global" , "glossary" (two separate strings).. How many other answers follow that to the letter? @ThomasKwa – Zach Gates Nov 4 '15 at 1:18
• "takes two strings" is the language used by OP; usually when something like that is mentioned without any qualifiers, it refers to one of our default I/O, which means we can take one string from the command line and one from STDIN, or an array of two strings, or whatever else follows those rules. – lirtosiast Nov 4 '15 at 1:24
• I think you're taking my answer a bit too seriously. This is just a fun submission and my best attempt at beating a built-in. If OP doesn't like the output format, so be it; I'll remove my answer. @ThomasKwa – Zach Gates Nov 4 '15 at 1:28
• How about print(exit()if a!=b else a,end='')? I don't know if that'll work or not, but it might – Beta Decay Nov 4 '15 at 6:53

TeaScript, 16 bytes 20

xf»l¦y[i]?1:b=0)


Takes each input separated by a space.

PHP, 52 bytes

Not spectacular but does the job:

$a=$argv;while($a[1][$i]==$a[2][$i])echo$a[1][$i++];


Takes two command line arguments:

php prefix.php department depart

• PHP7 lets you save another byte while(($a=$argv)[1][$i]==$a[2][$i])echo$a[1][$i++]; - Another PHP7 only solution (and best I could come up with @ 50 bytes) <?=substr(($a=$argv)[1],0,strspn($a[1]^\$a[2],~ÿ)); - Make sure your editor is in ascii mode, it's important the ~ÿ does not get converted to unicode. – Leigh Nov 27 '15 at 14:22