Самый длинный общий префикс из 2 строк


30

Напишите программу, которая принимает 2 строки в качестве входных данных и возвращает самый длинный общий префикс. Это , поэтому выигрывает ответ с наименьшим количеством байтов.

Test Case 1:

"global" , "glossary"
"glo"


Test Case 2:

"department" , "depart"
"depart"

Test Case 3:

"glove", "dove"
""

1
Еще один хороший тестовый пример "aca", "aba".
Морган Трепп

2
Вы хотите законченные программы, которые вводят из STDIN и печатают в STDOUT, или функции в порядке?
xnor

2
Можем ли мы предположить, что на входе не будет новых строк? Какие символы будут вводить?
Downgoat

5
Общее примечание: люди, использующие решение на основе регулярных выражений, не должны копировать ответы других, не проверяя их самостоятельно; это не работает во всех двигателях регулярных выражений. В частности, он дает разные (оба неправильные) ответы в nvi и vim.
Random832

1
Все приведенные примеры в нижнем регистре, но нужно ли нам беспокоиться о чувствительности к регистру? Например, должен globalи GLOSSARYвернуть gloили ''?
AdmBorkBork

Ответы:


22

Python 3, 54 байта

Спасибо Python за наличие встроенной функции для этой задачи! : D

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

Принимает ввод в виде двух слов, разделенных пробелом, например glossary global.


21

Haskell, 29 байт

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

Использование:

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

Рекурсивно определяет двоичную функцию %путем сопоставления с образцом. В двух строках с одинаковыми первыми буквами принимает эти первые буквы и добавляет их к функции остальных строк. На что-нибудь еще выдает пустую строку.


11

Pyth, 8 7 байтов

e@F._MQ

Спасибо @isaacg за 1 байт

Принимает ввод в кавычки и запятую, как "abc", "acc". Это происходит при ошибке (но оставляет стандартный вывод пустым), когда результатом является пустая строка. Если это недопустимо, добавьте 2 байта для#e@F._MQq

Тестирование

объяснение

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

Для того, чтобы результат пустая строка без ошибок: e|@F._M.z]k.
kirbyfan64sos

@ kirbyfan64sos Я полагаю, что то, что я вкладываю в окружение, на #...qодин байт меньше, я отредактирую в полном коде, думаю, это сбивает с толку
FryAmTheEggman

1
Возьмите ввод в форме, "abc", "def"и вы можете использовать Qвместо.z
isaacg

10

C ++, 101 100 99 байт

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

Считывает две строки из stdin, печатает символ в текущей позиции из одной из строк, в то время как символ в текущей позиции равен символу в той же позиции в другой строке.

Спасибо Zereges за сохранение одного байта.


4
Это прекрасное и пугающее использование этого forзаявления ...
Джошпбаррон,

Цикл не завершится, если строки будут равны.
Джон Траунтвейн

2
Не будет работать для строк, содержащих пробелы. Вы можете сохранить один байт, сделав int iв глобальном пространстве (чтобы он был инициализирован 0)
Zereges

@JonTrauntvein Я думаю, что это дело UB (?). Это работает ™ для меня, хотя. (gcc-5.1)
sweerpotato

9

Haskell, 38 байт

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

Пример использования: ( ((map fst.fst.span(uncurry(==))).).zip ) "global" "glossary"-> "glo".

Zip обе входные строки в список пар символов. Сделайте из него два списка: первый со всеми парами с начала до тех пор, пока оба символа равны, второй со всеми остальными. Удалите второй список и извлеките все символы из первого списка.


9

CJam, 12 11 9 байт

l_q.-{}#<

Это читает строки на две отдельные линии с Unix-стиле конца строки, то есть <string>\n<string>\n.

Спасибо @ MartinBüttner за -1 байт и @ jimmy23013 за -2 байта!

Попробуйте онлайн в интерпретаторе CJam .

Как это работает

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.

Черт, я не могу поверить, что мой самый первый ответ был так близок!
геокавель

1
Вы можете немного обмануть, предполагая завершающий перевод строки и использование l_q.-.
Джимми23013

@ jimmy23013 Это стандартно для ввода в Unix-подобных ОС, так почему бы и нет? Благодарность!
Деннис

8

APL, 13

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

Это функция, которая принимает массив из двух строк и возвращает префикс:

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

Действительно ли справедливо сказать, что алфавит APL - это алфавит байтовых символов? Или это стандартная практика здесь?
Filipq

9
@Filipq Ответы здесь используют наиболее естественную для языка кодировку. У APL есть собственная кодовая страница, в которой каждый символ представляет собой один байт.
Алекс А.

7

AppleScript, 215 байт

И я так старался ...; (

установить x в (отображать диалог "" ответ по умолчанию "") возвращаемый текст
установить a (отобразить диалог "" ответ по умолчанию "") возвращаемый текст
установите n в 1
установить "в"
повторить, в то время как пункт x = элемент n
установить o для o & x's item n
установите n в n + 1
конец
о

Я хотел бы видеть , насколько хорошо AppleScript может осуществить это, и человек является не построен для сравнения строк.


12
AppleScript не был создан ни для чего .
kirbyfan64sos

Единственное, чем я пользуюсь, кроме ужасных гольфов, это tell app "System Events" to <something>. Это является интересно посмотреть , как это имеет дело с такого рода вещи, хотя. @ kirbyfan64sos
Эддисон Крамп


6

Сед, 18

Я имел в виду что-то гораздо более длинное и сложное, так что заслуга этой идеи принадлежит @ kirbyfan64sos .

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

Включает +1 за -rопцию sed.


Какова была ваша оригинальная идея?
kirbyfan64sos

@ kirbyfan64sos Это в основном включало циклический переход между символами и остановку при несовпадении. Это была просто идея - без кода.
Цифровая травма

6

CJam, 12 8 26

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

Попробуйте онлайн.

(Есть идея использовать. = Вместо .- после просмотра ответа Денниса.)

Со всеми крайними случаями начинающему CJam, как я, стало трудно держать это коротким. Надеюсь, это по крайней мере работает для всех случаев.


6

C #, 201 147 байтов

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

Я знаю, что это не очень конкурентоспособно. Я просто хотел посмотреть, как это будет выглядеть.

РЕДАКТИРОВАТЬ: Спасибо Эш Бурлакзенко, Беренд и Деннис_Е


2
Просто получить ответ C # до 250 байт является конкурентоспособным. Кроме того, ты не можешь просто using System.*?
хлопнуть

1
.ForEach(x=>Console.Write(x))может быть сокращено до.ForEach(Console.Write)
Эш Бурлаченко

1
using System.Collections.Generic;не нужно Сбрейте еще один байт, удалив пробел из string[] a.
Беренд

2
1-е Containsненужно. 2-Вы можете сохранить несколько байтов, удалив using System;и сказав System.Console.Write;3-Этот код возвращает неправильный результат ("a") для ввода "aab", "aaab" из-за IndexOf. Самое короткое исправление, о котором я могу подумать, это использование a[0].Take(a[1].Length)Это длиной 147 байт: «использование System.Linq; класс 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

Спасибо за комментарии, когда я получу перерыв, я внимательно посмотрю на все из них, особенно на комментарий Dennis_E.
Jakotheshadows

5

Common Lisp, 39

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

Принимает два строковых аргумента, определяет индекс i, где они отличаются, и возвращает подстроку от 0 до i .


5

Perl 5, 20 19 18 байт

19 байт плюс 1 за -Eфлаг вместо -e:

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

Это скопировано бесстыдно от Digital Trauma «s SED ответа . Предполагается, что ввод представляет собой пару слов без пробелов в них (или перед первым) и с одним пробелом между ними.


Обновить:

ThisSuitIsBlackNot предложил использовать -peдля сохранения байта следующее (спасибо!):

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

И тогда Luk Storms предложил использовать -nEследующее для сохранения другого байта (спасибо!):

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

(Я считаю -Eкак один байт вместо стандартного -e, но -nили -pкак два. У меня сложилось впечатление, что это СОП здесь.)


1
« -M5.010при необходимости - бесплатно» . За один и тот же мета пост -peили -neбудет 1 дополнительный байт, а не 2. Таким образом, perl -nE 'say/^(.*).* \1/'получится 16 байт.
ThisSuitIsBlackNot

4

Python 3, 72

31 байт сохранен благодаря FryAmTheEggman. 8 сохранено благодаря DSM.

r=''
for x,y in zip(input(),input()):
 if x==y:r+=x
 else:break
print(r)

Без чего бы обходились программисты Python zip? : D
бета-распад

7
@BetaDecay Наша муха будет открыта все время.
Морган Трепп

Вы можете поместить input()s в zipи сохранить aи bсвязывание.
DSM

@DSM Ооо, хорошая мысль. Благодарность!
Морган Трепп

4

Python 3, 47

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

Функция, которая принимает список wиз двух слов и печатает общий префикс перед завершением с ошибкой.

printФункция Python 3 позволяет печатать строки вплотную друг к другу print(end=c)(спасибо Sp3000 за сохранение 3 байтов с этим более коротким синтаксисом). Это многократно берет две буквы из слов и печатает первую из букв. Индексация c[c!=d]выдает ошибку «за пределами», при которой c!=dпрекращается выполнение, когда встречаются две неравные буквы.

Явный цикл for на один символ длиннее, чем понимание списка:

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

Вот Это Да! Я даже не думал об использовании функции! Хороший. +1
Зак Гейтс

Только видел это сейчас, но как насчет print(end=c[c!=d])?
Sp3000

1
@ Sp3000 Ничего себе, я никогда не связывал, чтобы основной аргумент printбыл необязательным, означал, что его можно вызывать только с конечным аргументом, и он может содержать строку. Это действительно полезный трюк в целом. Вы должны сделать чаевые.
xnor

3

Javascript ES6, 52 байта

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

Использование:

>> f("global","glossary")
"glo"

Не работает с ada,aca...
flawr

Упс, исправлено. Забыл убить фильтрацию после того, как строки больше не совпадают.
Дендробиум

1
Вам не нужно называть функцию, так что вы можете f=
опустить

1
Вы можете сделать это меньше с картой(a,b)=>[...a].map((e,i)=>e==b[i]?e:b='').join``
Shaun H

2

Сетчатка , 14 байт

Использует ту же идею, что и kirbyfan64sos . К сожалению, несмотря на утверждение Мартина о том, что в конечном итоге режим соответствия будет содержать способ печати групп захвата, он еще не реализован. В противном случае (.*).* \1может использоваться вместе с 2 байтами или около того для некоторой еще не существующей опции строки конфигурации.

(.*).* \1.*
$1

Каждая строка будет идти в своем собственном файле с добавлением 1 байта на каждый дополнительный файл. В качестве альтернативы, запустите в одном файле с -sфлагом.


Эквивалентное регулярное выражение не соответствует в vim из-за жадности (а не-жадное регулярное выражение будет соответствовать самой короткой подстроке, т.е. пустой), вы уверены, что это работает?
Random832

@ Random832 Попробуйте использовать этот тестер для замены регулярных выражений, отметив опцию .NET. Установите операцию «заменить» и поместите шаблоны в соответствующие поля. Это не может не совпадать, если он должен быть. Как это могло потерпеть неудачу из-за жадности? Это единственная причина, по которой это работает. \1гарантирует, что оба слова начинаются с одинакового префикса. Поэтому независимо от того , как жадный (.*)это, \1не одно и то же.
mbomb007

В vim он вообще отказывается совпадать - я думаю, что он находит более длинную строку для первой (. *), Затем не может сопоставить ее с \ 1, а затем неправильно возвращает обратно к более коротким строкам.
Random832

@ Random832 Тогда вам нужно найти что-то еще, чтобы проверить свои регулярные выражения.
mbomb007

2

К, 24 байта

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

Найдите минимальную длину каждой строки. ( (&/#:'x)). Обрежьте каждую строку до этой длины ( #'x). Затем сравните, намажьте и суммируйте полученную последовательность:

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

Наконец, возьмите столько символов из первой предоставленной строки ( #*x).

В бою:

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

2

Powershell, 65 байт

Сравнивайте строки, сжимая первую, пока она не совпадет (напечатайте и выйдите) или пока строка не станет нулевой и цикл не завершится.

param($a,$b)while($a){if($b-like"$a*"){$a;exit}$a=$a-replace".$"}

2

Юлия, 62 байта

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

Исправлена ​​проблема (при огромных затратах в 14 байт) благодаря xnor!


2

C99, 73 байта

main(int c,char *a[]){for(char *x=a[1],*y=a[2];*x==*y++;putchar(*x++));}

Аналогичен этому ответу , но короче и соответствует спецификации (принимает данные из stdin).


Спец не говорит, что вход должен исходить от стандартного ввода. Это на самом деле длиннее, чем другой ответ, если вы добавите #include<stdio.h>, что необходимо для компиляции программы.
Мусаритмия

@AndrewCashner - он не обязательно должен быть на stdin, но он должен принимать данные. Другой ответ жестко закодирован. Кроме того, gcc жалуется на неявное использование, но прекрасно компилируется без включения.
Коминтерн

Гораздо короче без временных: main(int c,char**a){for(;*a[1]==*a[2]++;putchar(*a[1]++));}(59 байт).
Тоби Спейт

2

MATLAB, 50 40 байт

Определяет функцию, которая принимает 2 строки в качестве входных данных, выводит в командное окно

function t(a,b);a(1:find([diff(char(a,b)) 1],1)-1)

Это решение будет работать для любой строки, выходы

ans =

   Empty string: 1-by-0

если нет совпадения

Можно использовать с помощью скрипта вместо функции (используя локальные переменные a, b) (-16 байт).

так получая 34 байта

a(1:find([diff(char(a,b)) 1],1)-1)

Стиль функции (который кажется принятым стилем) дает

@(a,b)a(1:find([diff(char(a,b)) 1],1)-1)

(Спасибо @ Стиви Гриффин)


40 байт: @(a,b)a(1:find([diff(char(a,b)) 1],1)-1). =)
Стьюи Гриффин

2

Perl 6 , 28 байт

Я придумал два, которые берут свои значения из STDIN, которые основаны на ответе Perl 5.

lines~~/(.*).*' '$0/;say ~$0
lines~~/:s(.*).* $0/;say ~$0

Первый требует ровно один пробел между входами, а другой требует как минимум один символ пробела между входами.


Это немного короче, чем первое, что я попробовал, который берет значения из командной строки.

say [~] map ->($a,$b){$a eq$b&&$a||last},[Z] @*ARGS».comb # 58 bytes

или даже лямбда-версия этого:

{[~] map ->($a,$b){$a eq$b&&$a||last},[Z] @_».comb} # 52 bytes

Хотя это гораздо проще настроить, чтобы он принимал любое количество входных строк, за счет одного удара.

{[~] 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 `(@_,)`

2

Japt, 27 байт

Japt - это сокращенная версия Ja vaScri pt . переводчик

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

(Строки идут в поле ввода , например , так: "global" "glossary")

Этот код в точности эквивалентен следующему JS:

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

Я еще не реализовал анонимные функции, для чего и $...$существует: все, что находится между знаками доллара, остается нетронутым при переходе на JS. После добавления функций этого 21-байтового кода будет достаточно:

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

И после того, как я реализую еще несколько функций, в идеале это будет 18 байт:

UmXY{AxX=VgY ?X:AP

Предложения приветствуются!


Получается, что эта программа занимает всего 15 байт в современном Japt:

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

Попробуйте онлайн!


2

MATL , 11 9 байт

y!=XdYpf)

Попробуйте онлайн!

(-2 байта благодаря Джузеппе)

 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

Благодарность! yИдея довольно хорошо, я пытался что - то вроде начальной itiвместо 1Gw, но не думать об использовании yдля этого.
sundar - Восстановить Монику

1

Clojure / ClojureScript, 51

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

Довольно просто. К сожалению, пробелы вокруг параметра разрушения необходимы (вот и [a & b]все). Не самый короткий, но я прибил некоторые другие ответы на языках, которые любят хвастаться их краткостью, поэтому я отправлю это.


1

Python 2, 50 байт

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

вход

Ввод принимается в виде двух строк:

"global", "glossary"

Выход

Вывод - это каждый символ, за которым следует пробел; что, надеюсь, не проблема. Однако, если это так, я отредактирую свой ответ.

g l o 

Я почти уверен, что это неверно; спецификация ясно дала формат вывода в виде строки без пробелов.
Lirtosiast

Ну да, но входные данные также были даны в формате "global" , "glossary"(две отдельные строки). Сколько других ответов следует за письмом? @ThomasKwa
Зак Гейтс

«принимает две строки» - язык, используемый OP; обычно, когда что-то подобное упоминается без каких-либо определителей, это относится к одному из наших вводов- выводов по умолчанию , что означает, что мы можем взять одну строку из командной строки и одну из STDIN, или массив из двух строк, или что-либо еще после этих правила.
lirtosiast

Я думаю, вы слишком серьезно относитесь к моему ответу. Это просто забавная подача и моя лучшая попытка обыграть встроенную. Если OP не нравится формат вывода, пусть будет так; Я удалю свой ответ. @ThomasKwa
Зак Гейтс

Как насчет print(exit()if a!=b else a,end='')? Я не знаю, сработает ли это или нет, но это может
произойти

1

TeaScript, 16 байт 20

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

Принимает каждый вход через пробел.


1

PHP, 52 байта

Не впечатляет, но делает работу:

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

Принимает два аргумента командной строки:

php prefix.php department depart

PHP7 позволяет вам сохранить еще один байт. while(($a=$argv)[1][$i]==$a[2][$i])echo$a[1][$i++];- Еще одно решение для PHP7 (и лучше всего, если бы я смог получить @ 50 байт). <?=substr(($a=$argv)[1],0,strspn($a[1]^$a[2],~ÿ));- Убедитесь, что ваш редактор работает в режиме ascii, важно, чтобы ~ÿон не конвертировался в юникод.
Ли
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.