Préfixe commun le plus long de 2 chaînes

30

Écrivez un programme qui prend 2 chaînes en entrée et retourne le préfixe commun le plus long. Il s'agit de , donc la réponse avec le plus petit nombre d'octets l'emporte.

Test Case 1:

"global" , "glossary"
"glo"


Test Case 2:

"department" , "depart"
"depart"

Test Case 3:

"glove", "dove"
""
Lawrence V.
la source
1
Un autre bon cas de test est "aca", "aba".
Morgan Thrapp du
2
Voulez-vous des programmes complets qui saisissent depuis STDIN et imprime vers STDOUT, ou les fonctions sont-elles OK?
xnor
2
Pouvons-nous supposer que l'entrée n'aura pas de nouvelles lignes? Quels caractères l'entrée aura-t-elle?
Downgoat
5
Remarque générale: les personnes utilisant une solution basée sur des expressions rationnelles ne doivent pas copier les réponses regex d'autres personnes sans les tester vous-même; cela ne fonctionne pas dans tous les moteurs regex. En particulier, il donne des réponses différentes (toutes deux incorrectes) dans nvi et vim.
Random832
1
Tous les exemples donnés sont en minuscules, mais devons-nous nous soucier de la sensibilité à la casse? Par exemple, devrait globalet GLOSSARYretourner gloou ''?
AdmBorkBork

Réponses:

22

Python 3, 54 octets

Merci Python d'avoir une fonction intégrée pour cette tâche! :RÉ

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

Prend la saisie sous la forme de deux mots séparés par un espace tel que glossary global.

Beta Decay
la source
21

Haskell, 29 octets

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

Usage:

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

Définit récursivement la fonction binaire %par correspondance de modèle. Sur deux chaînes avec des premières lettres égales, prend ces premières lettres et les ajoute à la fonction du reste des chaînes. Sur toute autre chose, donne la chaîne vide.

xnor
la source
11

Pyth, 8 7 octets

e@F._MQ

Merci @isaacg pour 1 octet de moins

Prend les entrées entre guillemets et séparées par des virgules, comme "abc", "acc". Cela se termine sur une erreur (mais laisse stdout vide) lorsque le résultat est la chaîne vide. Si cela est inacceptable, ajoutez 2 octets pour#e@F._MQq

Suite de tests

Explication

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
FryAmTheEggman
la source
Pour le résultat de la chaîne vide sans erreur: e|@F._M.z]k.
kirbyfan64sos
@ kirbyfan64sos Je crois que la chose que j'ai mise pour l'entourer #...q est d'un octet de moins que cela, je vais éditer dans le code complet, je suppose que c'est déroutant
FryAmTheEggman
1
Prenez la saisie dans le formulaire "abc", "def"et vous pouvez utiliser Qau lieu de.z
isaacg
10

C ++, 101 100 99 octets

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

Lit deux chaînes de stdin, imprime le caractère à la position actuelle de l'une des chaînes tandis que le caractère à la position actuelle est égal au caractère à la même position dans l'autre chaîne.

Merci à Zereges d' avoir enregistré un octet.

patate douce
la source
4
C'est une belle et terrifiante utilisation de la fordéclaration ...
Joshpbarron
La boucle ne se terminerait pas si les chaînes étaient égales.
Jon Trauntvein
2
Ne fonctionnera pas pour les chaînes contenant des espaces blancs. Vous pouvez enregistrer un octet, en faisant int idans l'espace global (pour qu'il soit 0 initialisé)
Zereges
@ JonTrauntvein Je pense que ce cas est UB (?). Cela fonctionne ™ pour moi cependant. (gcc-5.1)
patate douce
9

Haskell, 38 octets

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

Exemple d'utilisation: ( ((map fst.fst.span(uncurry(==))).).zip ) "global" "glossary" -> "glo".

Compressez les deux chaînes d'entrée dans une liste de paires de caractères. Faites-en deux listes: la première avec toutes les paires depuis le début tant que les deux caractères sont égaux, la seconde avec tous les autres. Supprimez la deuxième liste et extrayez tous les caractères de la première liste.

nimi
la source
9

CJam, 12 11 9 octets

l_q.-{}#<

Cela lit les chaînes sur deux lignes distinctes avec une fin de ligne de style Unix, c'est-à-dire, <string>\n<string>\n .

Merci à @ MartinBüttner pour -1 octet et à @ jimmy23013 pour -2 octets!

Essayez-le en ligne dans l' interpréteur CJam .

Comment ça marche

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.
Dennis
la source
Darn, je ne peux pas croire que ma toute première réponse était si proche!
geokavel
1
Vous pouvez tricher un peu en supposant une nouvelle ligne de fin et l'utiliser l_q.-.
jimmy23013
@ jimmy23013 C'est standard pour l'entrée sur les OS de type Unix, alors pourquoi pas? Merci!
Dennis
8

APL, 13

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

Il s'agit d'une fonction qui prend un tableau de deux chaînes et renvoie le préfixe:

      {⊃↓K/⍨=⌿K←↑⍵}'glossary' 'global'
glo
      {⊃↓K/⍨=⌿K←↑⍵}'department' 'depart'
depart
marinus
la source
Est-il vraiment juste de dire que l'alphabet APL est un alphabet de caractères de taille octet? Ou est-ce une pratique courante ici?
Filipq
9
@Filipq Les réponses utilisent ici l'encodage le plus naturel de la langue. APL a sa propre page de codes sur laquelle chaque caractère est un seul octet.
Alex A.
7

AppleScript, 215 octets

Et j'ai tellement essayé ...; (

mettre x à (afficher la boîte de dialogue "" réponse par défaut "")
définir le texte de (boîte de dialogue "" réponse par défaut "") renvoyé à
mettre n à 1
mettre o à ""
répéter pendant que l'élément de n n = l'élément de a n
définir o sur o & x l'élément n
définir n sur n + 1
fin
o

Je voulais voir dans quelle mesure AppleScript pouvait réussir cela, et l' homme n'est-il pas conçu pour des comparaisons de chaînes.

Addison Crump
la source
12
AppleScript n'a été conçu pour rien .
kirbyfan64sos
La seule chose que je l'utilise pour les golfs est terrible tell app "System Events" to <something>. Cependant, il est intéressant de voir comment il traite ce genre de choses. @ kirbyfan64sos
Addison Crump
6

rs , 14 octets

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

Démonstration en direct et cas de test.

C'est assez simple. Il correspond simplement au ... préfixe commun le plus long et supprime le reste de la chaîne. S'il n'y a pas de préfixe commun le plus long, il efface simplement tout.

kirbyfan64sos
la source
6

sed, 18

J'avais quelque chose de beaucoup plus long et de plus compliqué à l'esprit, donc le mérite de cette idée revient à @ kirbyfan64sos .

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

Comprend +1 pour l' -roption de sed.

Traumatisme numérique
la source
Quelle était votre idée originale?
kirbyfan64sos
@ kirbyfan64sos Cela impliquait essentiellement de parcourir les caractères un par un et de s'arrêter en cas de décalage. Ce n'était qu'une idée - pas de code derrière.
Digital Trauma
6

CJam, 12 8 26

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

Essayez-le en ligne.

(J'ai eu l'idée d'utiliser. = Au lieu de .- après avoir regardé la réponse de Dennis.)

Avec tous les cas de bord, il est devenu difficile pour un débutant CJam comme moi de rester bref. Espérons que cela fonctionne au moins pour tous les cas.

geokavel
la source
6

C #, 201 147 octets

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);}}

Je sais que ce n'est pas terriblement compétitif. Je voulais juste voir à quoi ça ressemblerait.

EDIT: Merci Ash Burlakzenko, Berend et Dennis_E

Jakotheshadows
la source
2
Le simple fait d'obtenir une réponse C # sous 250 octets est compétitif. Aussi, ne pouvez-vous pas simplement using System.*?
clap
1
.ForEach(x=>Console.Write(x))pourrait être raccourci à.ForEach(Console.Write)
Ash Burlaczenko
1
using System.Collections.Generic;est inutile. Raser un octet de plus en supprimant l'espace de string[] a.
Berend
2
1-Le Containsn'est pas nécessaire. 2-Vous pouvez enregistrer quelques octets en supprimant using System;et en disant System.Console.Write;3-Ce code renvoie le mauvais résultat ("a") pour l'entrée "aab", "aaab", à cause de IndexOf. Le correctif le plus court auquel je pourrais penser est d'utiliser a[0].Take(a[1].Length)Il fait 147 octets de 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
Merci pour les commentaires quand j'aurai une pause, je les examinerai tous en particulier le commentaire de Dennis_E.
Jakotheshadows
5

Lisp commun, 39

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

Prend deux arguments de chaîne, détermine l'index i où ils diffèrent et renvoie une sous-chaîne de 0 à i .

Joshua Taylor
la source
5

Perl 5, 20 19 18 octets

19 octets, plus 1 pour le -Edrapeau au lieu de -e:

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

Ceci est copié sans vergogne du numérique Trauma de réponse sed . Il suppose que l'entrée est un couple de mots sans espaces (ou avant le premier) et avec un espace entre eux.


Mise à jour:

ThisSuitIsBlackNot a suggéré d'utiliser -pecomme suit, pour enregistrer un octet (merci!):

($_)=/^(.*).* \1/

Et puis Luk Storms a suggéré d'utiliser -nEcomme suit pour enregistrer un autre octet (merci!):

say/^(.*).* \1/

(Je compte -Ecomme un octet au lieu de la norme -e, mais -nou -pcomme deux. Mon impression est que ce SOP est ici.)

msh210
la source
1
" -M5.010, si nécessaire, est gratuit" . Par le même message de méta, -peou -neserait 1 octet supplémentaire, pas 2. Donc perl -nE 'say/^(.*).* \1/', marquerait 16 octets.
ThisSuitIsBlackNot
4

Python 3, 72

31 octets économisés grâce à FryAmTheEggman. 8 sauvés grâce à DSM.

r=''
for x,y in zip(input(),input()):
 if x==y:r+=x
 else:break
print(r)
Morgan Thrapp
la source
De quoi les programmeurs Python se passeraient-ils zip? : D
Beta Decay
7
@BetaDecay Notre mouche serait ouverte tout le temps.
Morgan Thrapp du
Vous pouvez mettre le input()s dans le zipet enregistrer le aet la bliaison.
DSM
@DSM Ooo, bon point. Merci!
Morgan Thrapp,
4

Python 3, 47

def f(w):[print(end=c[c!=d])for c,d in zip(*w)]

Une fonction qui prend une liste wde deux mots et imprime le préfixe commun avant de se terminer par une erreur.

La printfonction de Python 3 vous permet d'imprimer les chaînes les unes contre les autres print(end=c)(grâce au Sp3000 pour avoir économisé 3 octets avec cette syntaxe plus courte). Cela prend à plusieurs reprises deux lettres des mots et imprime la première des lettres. L'indexation c[c!=d]donne une erreur hors limites où c!=d, mettant fin à l'exécution lorsque deux lettres inégales sont rencontrées.

Une boucle for explicite est un caractère plus long que la compréhension de la liste:

def f(w):
 for c,d in zip(*w):print(end=c[c!=d])
xnor
la source
Hou la la! Je n'avais même pas pensé à utiliser une fonction! Joli. +1
Zach Gates
Je ne l'ai vu que maintenant, mais qu'en est-il print(end=c[c!=d])?
Sp3000
1
@ Sp3000 Wow, je ne me suis jamais connecté que l'argument principal d' printêtre facultatif signifiait qu'il pouvait être appelé avec uniquement l'argument de fin, et qui pouvait contenir la chaîne. C'est une astuce vraiment utile en général. Vous devriez faire un pourboire.
2015 à 7h49
3

Javascript ES6, 52 octets

f=(a,b)=>[...a].filter((e,i)=>e==b[i]?1:b='').join``

Usage:

>> f("global","glossary")
"glo"
Dendrobium
la source
Ne fonctionne pas avec ada,aca...
flawr
Oups, fixe. Vous avez oublié de supprimer le filtrage après que les chaînes ne correspondent plus.
Dendrobium
1
Vous n'avez pas besoin de nommer la fonction, vous pouvez donc f=
omettre
1
vous pouvez le faire plus petit avec la carte(a,b)=>[...a].map((e,i)=>e==b[i]?e:b='').join``
Shaun H
2

Rétine , 14 octets

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.

mbomb007
la source
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
@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
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
@Random832 Then you need to find something else to test your regexes on.
mbomb007
2

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")
JohnE
la source
2

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".$"}
Jonathan Leech-Pepin
la source
2

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!

Alex A.
la source
2

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

Comintern
la source
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
@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
Much shorter without the temporaries: main(int c,char**a){for(;*a[1]==*a[2]++;putchar(*a[1]++));} (59 bytes).
Toby Speight
2

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)

Jonas
la source
40 bytes: @(a,b)a(1:find([diff(char(a,b)) 1],1)-1). =)
Stewie Griffin
2

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 `(@_,)`
Brad Gilbert b2gills
la source
2

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!

ETHproductions
la source
2

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
sundar - Reinstate Monica
la source
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
1

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.

MattPutnam
la source
1

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 
Zach Gates
la source
I'm pretty sure this is invalid; the spec clearly gave the output format as a string without spaces.
lirtosiast
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
"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
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
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
1

TeaScript, 16 bytes 20

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

Takes each input separated by a space.

Downgoat
la source
1

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
insertusernamehere
la source
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