Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Regexp finding longest common prefix of two strings

Is there a regexp which would find longest common prefix of two strings? And if this is not solvable by one regexp, what would be the most elegant piece of code or oneliner using regexp (perl, ruby, python, anything).

PS: I can do this easily programatically, I am asking rather for curiosity, because it seems to me that this could be solveable by regexp.

PPS: Extra bonus for O(n) solution using regexps. Come on, it should exist!

like image 574
gorn Avatar asked Feb 02 '12 14:02

gorn


People also ask

How do you find the longest common prefix between two strings?

Given the array of strings S[], you need to find the longest string S which is the prefix of ALL the strings in the array. Longest common prefix (LCP) for a pair of strings S1 and S2 is the longest string S which is the prefix of both S1 and S2. For Example: longest common prefix of “abcdefgh” and “abcefgh” is “ABC”.

What is the longest common prefix?

The longest common prefix for an array of strings is the common prefix between 2 most dissimilar strings. For example, in the given array {“apple”, “ape”, “zebra”}, there is no common prefix because the 2 most dissimilar strings of the array “ape” and “zebra” do not share any starting characters.

How do you find the common prefix in C++?

However, for C++ it would also generally be better to use the std::string type. You can use std::getline(std::cin, my_std_string) to read lines, and prefix = my_std_string. substr(0, i) would be a way to copy part of a string.


2 Answers

If there's some character that neither string contains —, say, \0 — you could write

"$first\0$second" =~ m/^(.*).*\0\1/s; 

and the longest common prefix would be saved as $1.


Edited to add: This is obviously very inefficient. I think that if efficiency is a concern, then this simply isn't the approach we should be using; but we can at least improve it by changing .* to [^\0]* to prevent useless greediness that will just have to be backtracked again, and wrapping the second [^\0]* in (?>…) to prevent backtracking that can't help. This:

"$first\0$second" =~ m/^([^\0]*)(?>[^\0]*)\0\1/s; 

This will yield the same result, but much more efficiently. (But still not nearly as efficiently as a straightforward non–regex-based approach. If the strings both have length n, I'd expect its worst case to take at least O(n2) time, whereas the straightforward non–regex-based approach would take O(n) time in its worst case.)

like image 174
ruakh Avatar answered Sep 23 '22 12:09

ruakh


Here's a Python one-liner:

>>> a = 'stackoverflow' >>> b = 'stackofpancakes' >>> a[:[x[0]==x[1] for x in zip(a,b)].index(0)] 0: 'stacko' >>> a = 'nothing in' >>> b = 'common' >>> a[:[x[0]==x[1] for x in zip(a,b)].index(0)] 1: '' >>>  
like image 34
Tebbe Avatar answered Sep 22 '22 12:09

Tebbe