Знайдіть оригінальний рядок, без повторення, без повторення посередині


25

Іноді трапляється, що під час введення речення я відволікаюсь і закінчую вводити одну і ту ж пару слів двічі пару слів двічі поспіль.

Щоб переконатися, що інших людей це не турбує, ваше завдання - написати програму, яка вирішить цю проблему!

Завдання

З огляду на рядок введення (якщо це має значення для вашої мови, ви можете припустити, що тільки для ASCII введення, яке не містить ліній передач.) str, Що містить десь у його середині підрядку, яка виникає двічі в негайній послідовності, поверніть рядок з одним екземпляром цього підрядку видалено

У випадку кількох можливостей поверніть найкоротший можливий варіант відповіді (тобто виберіть найдовший підряд, що повторюється, і повторно видаліть його).

У випадку декількох, однаково довгих послідовних повторів підрядів, видаліть першу (тобто першу, що виникає під час читання рядка спереду назад).

Ви можете припустити, що введення правильне (тобто завжди містить послідовну повторювану підрядку), що може допомогти переграти її.


Приклади

  1. Вхід: hello hello world-> Висновок: hello world.
  2. Вхід: foofoo-> Висновок: foo. (Отже: так, рядок може складатися з повторюваної частини лише два рази).
  3. Введення: aaaaa-> Вихід:, aaaоскільки тут знаходиться найдовша послідовна послідовна підрядка aa.
  4. Вхід: Slartibartfast-> Це неправдивий вхід, оскільки він не містить послідовних повторних підрядків, тому вам не потрібно обробляти цей випадок.
  5. Вхід: the few the bar-> Це ще один недійсний вхід, оскільки повторювана частина повинна негайно слідувати за початковою частиною. В цьому випадку, theі theвідокремлені один від одного ніж - то ще в проміжку між, так що цей вхід є неприпустимим.
  6. Вхід: ababcbc-> Висновок: abcbc. Дві можливі найдовші послідовні повторювані підрядки є abі bc. Як abзустрічається раніше у рядку, ця відповідь є правильною.
  7. Вхід: Buffalo buffalo Buffalo buffalo buffalo buffalo Buffalo buffalo. Вихід: Buffalo buffalo buffalo buffalo Buffalo buffalo. (Виконана заміна повинна враховувати регістри).
  8. Вхід: Sometimes it happens that while typing a sentence, I am distracted and I end up typing the same couple of words twice couple of words twice in succession.-> Висновок: Sometimes it happens that while typing a sentence, I am distracted and I end up typing the same couple of words twice in succession.. Видаляється лише найдовша послідовна повторювана підрядка.

Ваш код повинен бути якомога коротшим, оскільки це , тому найкоротша відповідь у байтах виграє. Удачі!


@manatwork Коли приймаєте перше речення, яке є Sometimes it happens that while typing a sentence, I am distracted and I end up typing the same couple of words twice couple of words twice in succession.вхідним, результат повинен бути Sometimes it happens that while typing a sentence, I am distracted and I end up typing the same couple of words twice in succession.. Видаляється лише найдовше знайдене дублювання.
Qqwy

1
Я пропоную додати тест, який має дві можливі заміни, коли другий довший, ніж перший. Я підозрюю, що більшість відповідей цього не пройде :)
1717

@aross test case 8 саме це :)
Qqwy

Якщо я і мій тестовий код не помиляємось, є лише одна повторена рядок.
1717

@aross є подвійна pвhappens
Qqwy

Відповіді:


8

Perl 6 , 40 байт

{.subst: m:ex/(.*))>$0/.max(*.chars),''}

Спробуй це

{
  .subst:             # substitute


    m                 # match
    :exhaustive
    /
      ( .* )          # any number of chars

      )>              # don't include the following in what is returned

      $0              # the first match again
    /.max( *.chars ), # find the first longest submatch


    ''                # substitute it with nothing
}

8

Сітківка , 35 33 байт

Кількість байтів передбачає кодування ISO 8859-1.

(?=(.+)(\1.*))
$2¶$`
O$#`
$.&
G1`

Спробуйте в Інтернеті!

Пояснення

Оскільки двигуни регексу шукають матчі зліва направо, знайти тривалий збіг не тривіально, незалежно від позиції. Це можна зробити з балансуючими групами .NET, але результат досить неприємно довгий:

1`((.)+)\1(?<=(?!.*((?>(?<-2>.)+).+)\3)^.*)
$1

Тому я зрозумів, що намагаюся уникнути цього, використовуючи деякі інші функції Retina.

(?=(.+)(\1.*))
$2¶$`

Почнемо з того, щоб по суті застосувати всі можливі заміни, по одному у кожному рядку. Для цього ми узгоджуємо позицію перед матчем (замість самого матчу), щоб дозволити збіги, що збігаються. Це робиться, вводячи справжній вираз в лукахед. Потім цей запит захоплює решту, за винятком дубліката, який ми хочемо видалити в групу 2. Ми записуємо назад групу 2 (видалення дубліката), передачу рядків, а потім весь вхід до матчу, що дає нам, в основному, новий рядок бути заміщеними.

Наприкінці у кожного матчу буде по одному рядку з відповідним дублікатом. Зрештою, ще раз буде повний вхід без будь-яких замін.

Тепер, коли у нас є всі можливі заміни, ми хочемо найкоротшого результату (який відповідає найдовшому видаленому повторенню).

O$#`
$.&

Тому ми спочатку сортуємо лінії за довжиною.

G1`

І тоді ми тримаємо лише перший рядок.


Нічого собі, що техніка заміни справді розумна!
Лев,

6

Желе , 22 19 байт

-2 байти завдяки Деннісу (уникайте зміни аргументів, видаліть надмірно приріст)

ẋ2³wȧ+¥J
ẆÇ€LÐṀḢṬœp

Спробуйте в Інтернеті!

Повна програма (виявлено помилку, що ÐṀне діє з правильною сутністю над діадами, яка буде виправлена ​​незабаром; хоча я не впевнений, що тут можна зробити коротший код).

Як?

Знаходить перший з найдовших фрагментів вводу таким, що на вході існує повторення, і видаляє його з введення.

ẋ2³wȧ+¥J - Link 1, removal indices for given slice if valid, else 0: slice, x
ẋ2       - repeat x twice, say y
  ³      - program input: s
   w     - index of first occurrence of y in s (1-based) or 0, say i
       J - range(length(x)): [1,2,3,...,length(x)]
      ¥  - last two links as a dyad
    ȧ    -     and (non-vectorising)
     +   -     addition: [1+i,2+i,3+i,...,length(x)+i] or 0
         - note: no need to decrement these since the last index will be the 1st index
         - of the repetition (thanks to Dennis for spotting that!)

ẆÇ€LÐṀḢṬœp - Main link: string, s
Ẇ          - all sublists of s (order is short to long, left to right, e.g. a,b,c,ab,bc,abc)
 Ç€        - call the last link (1) as a monad for €ach
    ÐṀ     - filter by maximal
   L       -     length
      Ḣ    - head: get the first (and hence left-most) one
       Ṭ   - untruth: make a list with 1s at the indexes given and 0s elsewhere
        œp - partition s at truthy indexes of that, throwing away the borders
           - implicit print

6

JavaScript (ES6), 81 74 байт

f=
s=>s.replace(/(?=(.+)\1)/g,(_,m)=>r=m[r.length]?m:r,r='')&&s.replace(r,'')
<input oninput=o.textContent=f(this.value)><pre id=o>

Редагувати: Збережено 7 байт, викравши m[r.length]трюк @ Арнольда .


5

PowerShell , 87 байт

param($s)([regex](([regex]'(.+)\1'|% *hes $s|sort L*)[-1]|% Gr*|% V*)[1])|% Re* $s '' 1

Спробуйте в Інтернеті! (усі тестові випадки)

Пояснення

Починаючи зсередини, ми працюємо Matchesз (.+)\1регулярним виразом, щоб повернути всі об'єкти відповідності для вказаного рядка. Зворотний вираз відповідає будь-якій послідовності символів, яка слідує за собою.

Потім отримані об'єкти відповідності переносяться на sortсортування за їх Lengthвластивістю (скорочується до підстановки). Це призводить до масиву збігів, відсортованих за довжиною, за зростанням, тому індексуйте з, [-1]щоб отримати останній елемент (найдовший). Значенням цього збігу є збіг, хоча не група, тому воно включає повторення, тому ми отримуємо об'єкт Group ( |% Gr*), а потім значення that ( |% V*), щоб отримати найбільшу повторювану рядок. Річ - об'єкт групи - це фактично масив, оскільки група 0 - це завжди збіг, але я хочу фактичну групу (1), тому отримане значення є фактично значенням s , отже, індексування для отримання другого елемента [1]. Це значення передається на сам об'єкт регулярного вираження, а потім наReplaceметод викликається проти оригінальної рядка, замінюючи нічим, і замінюється лише перший матч ( |% Re* $s '' 1).


5

Haskell , 101 байт

Основна функція полягає в тому f, що вона бере і повертає a String.

l=length
a=splitAt
f s|i<-[0..l s-1]=[p++t|n<-i,(p,(r,t))<-fmap(a$l s-n).(`a`s)<$>i,r==take(l r)t]!!0

Спробуйте в Інтернеті!

Коли я почав це, я імпортував Data.Listі використовується maximum, tails, initsі isPrefixOf. Якось це перетворилося на це. Але мені все ж вдалося лише поголити 11 байт ...

Примітки

  • splitAt/ aрозділяє рядок за заданим індексом.
  • s - це рядок введення.
  • i- це перелік чисел [0 .. length s - 1], -1щоб обійти цей splitAtрозділ в кінці, якщо їм задано занадто великий індекс.
  • nє length sмінусом поточної мети довжини для повторної частини, вона вибрана таким чином, тому нам не потрібно використовувати два списки чисел та / або багатослівний синтаксис списку зменшення.
  • p, rІ tє ходовим розколом s, з rНаміченим повторена частиною. fmapТам використовує , (,) String Functorщоб уникнути змінної для проміжного поділу.
  • !!0 вибирає перший елемент списку збігів.


4

Математика, 63 60 59 байт

4 байти збережено завдяки Мартіну Ендеру .

#&@@StringReplaceList[#,a__~~a__->a]~SortBy~{StringLength}&

Анонімна функція. Приймає рядок як вхідний і повертає рядок як вихідний.


Здається, це не працює на прикладі 6 - ~SortBy~StringLengthсортує рядки в алфавітному порядку, якщо їх довжини однакові ...
Не дерево

1
@ LegionMammal978 Коротше виправлення - це збереження SortByта загортання StringLengthсписку, щоб отримати стабільний сорт.
Мартін Ендер

3

JavaScript (ES6), 70 байт

s=>s.replace(s.match(/(.+)(?=\1)/g).reduce((p,c)=>c[p.length]?c:p),'')

Тестові справи


Не вдається aaaabaaab, але приємне використання reduce.
Ніл

2

Це має бути коментар, але у мене недостатньо репутації для коментарів. Я просто хочу сказати @Neil, що його код можна зменшити до 77 байт. Вам не потрібно використовувати твердження вперед в регулярному вираженні. Ось скорочена версія:

s=>s.replace(/(.+)\1/g,(_,m)=>(n=m.length)>l&&(l=n,r=m),l=0)&&s.replace(r,'')

2
Привіт, і ласкаво просимо до PPCG! Ви можете надіслати це як власну відповідь на JavaScript! Якщо ви хочете, я можу відредагувати вашу публікацію і показати вам, як вона повинна виглядати.
NoOneIsHere

2
Мені потрібно використовувати твердження вперед, щоб розібратися з випадками збігів, що збігаються. aabab- найкоротший приклад того, коли ваша пропозиція провалюється.
Ніл

0

C #, 169 байт

(s)=>{var x="";for(int i=0;i<s.Length-2;i++){for(int l=1;l<=(s.Length-i)/2;l++){var y=s.Substring(i,l);if(s.Contains(y+y)&l>x.Length)x=y;}}return s.Replace(x+x,x);}

Пояснення

(s) => {                // Anonymous function declaration    
    var x = "";         // String to store the longest repeating substring found
    for (int i = 0; i < s.Length - 2; i++) {               // Loop through the input string
        for (int l = 1; l <= (s.Length - i) / 2; l++) {    // Loop through all possible substring lengths
            var y = s.Substring(i, l);
            if (s.Contains(y + y) & l > x.Length) x = y;   // Check if the substring repeats and is longer than any previously found
        }
    }
    return s.Replace(x + x, x);    // Perform the replacement
}

Це підхід грубої сили: спробуйте всі можливі підрядки, поки ми не знайдемо найдовшу підрядку, що повторюється. Безперечно, Regex є більш ефективним, але спілкування з Regex в C #, як правило, є багатослівним.


Ласкаво просимо до PPCG! Усі відповіді повинні бути або повноцінними програмами, або функціями , що викликаються , а не впевненими фрагментами із введеннями у змінні з твердим кодом. Також, будь ласка, покажіть версію коду, яку ви насправді рахували за все видалене непотрібне пробіл. Ви завжди можете включити більш читану версію з відступом, окрім повністю гольф-версії.
Мартін Ендер

0

PHP, 84 82 байт

Примітка: використовується кодування IBM-850.

for($l=strlen($argn);--$l&&!$r=preg_filter("#(.{0$l})\g-1#",~█╬,$argn,1););echo$r;

Бігайте так:

echo 'hello hello world' | php -nR 'for($l=strlen($argn);--$l&&!$r=preg_filter("#(.{0$l})\g-1#",~█╬,$argn,1););echo$r;';echo
> hello world

Пояснення

for(
  $l=strlen($argn);   # Set $l to input length.
  --$l   &&           # Decrement $l each iteration until it becomes 0.
  !$r=preg_filter(    # Stop looping when preg_filter has a result
                      # (meaning a successful replace).
    "#(.{0$l})\g-1#", # Find any character, $l times (so the longest
                      # match is tried first), repeated twice.
    ~█╬,              # Replace with $1: first capture group, removing the
                      # duplicate.
    $argn,
    1                 # Only replace 1 match.
  );
);
echo$r;               # Print the result of the (only) successful
                      # search/replace, if any.

Налаштування

  • Збережено 2 байти, оскільки немає мінімальної довжини повторної підрядки
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.