Исправить мои заикающиеся слова

12

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

Пример написанного текста таким программным обеспечением может быть таким: «Пожалуйста, будьте осторожны» . В этом примере «осторожный» - это оригинальное слово, а «ca ca» - заикающиеся слова.

Вызов

Напишите программу или функцию, которая исправляет заикающиеся слова, удаляя их из входных данных, сохраняя оригинальные слова. Например, исправленная версия «пожалуйста, будьте осторожны» будет «пожалуйста, будьте осторожны» .

Это , выигрывает самый короткий ответ на любом языке!

Что заикаются слова?

Заикание имеет много разных вариаций. Но для простоты этого вызова мы собираемся ограничить его следующими правилами:

  • Заикающиеся слова могут быть незавершенной частью или целым оригинальным словом. Под «незавершенной частью» я подразумеваю, что первоначальное слово должно начинаться именно с заикающегося слова. Например, «ope» и «open» оба могут быть запутанным словом для «open» , но «pen» не может быть одним, поскольку «open» не начинается с «pen» .
  • Заикающиеся слова должны содержать хотя бы одну из гласных «aeiou» . Например, «звездочка» может быть запятнанным словом для «начала», так как оно содержит «а» , но «st» не может быть запутанным словом, поскольку оно не содержит ни одной из упомянутых гласных.
  • Заикающиеся слова могут появляться только перед исходным словом и должны быть повторены не менее двух раз, чтобы быть действительными (исходное слово не учитывается в повторах). Например, «oo open» содержит заикающиеся слова, а «o open o» - нет, потому что «o» после исходного слова не считается, а «o» перед исходным словом не повторяется по крайней мере два раза. «иди, иди, иди, иди, иди» имеет пять повторений заикающихся слов перед исходным словом и является действительным.
  • Один набор повторяющихся заикающихся слов не может содержать смешанные формы, и слова должны быть в точности похожи друг на друга. Например, «op o op open» не считается заикающимися словами. С другой стороны, «o op op open» содержит заикающиеся слова, потому что первое «o» здесь рассматривается как совершенно другое слово, а два «op» считаются заикающимися словами «open» .
  • В случае нескольких допустимых наборов повторяющихся заикающихся слов сразу друг за другом, остается только последнее оригинальное слово. Например, в «ооо оп оп оп открытым» , то «оо о» части рассматривается как заикался слова первого «оп» , поэтому они должны быть удалены , а затем «оп оп оп» рассматривается как заикался слова «открыта « И они тоже должны быть удалены, поэтому после удаления заикающихся слов останется только « открыть » . Вы можете предположить, что несколько допустимых наборов повторяющихся заиканных слов происходят только слева направо, поэтому исправление «op op ooo open» приведет к «op op open» (иначе

вход

  • Ввод - это строка из одной строки, содержащая только английские буквы ASCII (az), цифры (0-9) и пробелы. Буквенный регистр не важен, и вы можете решить принять строчные или прописные буквы или оба, но регистр должен остаться прежним, и вы не можете изменить его в выводе.
  • Вы можете использовать список букв (например ["l","i","s","t"," ","o","f"," ","l","e","t","t","e","r","s"]) вместо строки, но вы не можете использовать список слов. Если ваш язык имеет другую структуру ввода, используйте его. Дело в том, что входные данные не должны разделяться словами, поэтому стоимость разделения слов в некоторых языках может фактически вызвать другие творческие решения.
  • Входные данные могут содержать ни одного, одно или несколько заиканных слов в нем.
  • Слова и / или цифры разделяются одним пробелом, и ввод не будет содержать двойных пробелов рядом друг с другом.

Выход

  • Строка или список букв или соответствующая структура на вашем языке со всеми заикающимися словами, удаленными из ввода.
  • Выходные слова должны быть разделены ровно одним пробелом (так же, как ввод).
  • Допускается одиночная начальная и конечная строка или пробел.

Стандартные лазейки запрещены.

Контрольные примеры

Нет заикающихся слов:

"hello world" => "hello world"

Единственный случай повторяющихся заикающихся слов:

"ope ope ope ope open the window" => "open the window"

Многократные повторения заикающихся слов:

"there is is is is something un un under the the the table" => "there is something under the table"

Нет заикающихся слов, недостаточно повторяется

"give me the the book" => "give me the the book"

Нет заикающихся слов, не произносите ни одной из упомянутых гласных:

"h h help m m m me" => "h h help m m m me"

Числа не являются заиканными словами, у них нет ни одной из упомянутых гласных:

"my nu nu number is 9 9 9 9876" => "my number is 9 9 9 9876"

Но слово с гласными и цифрами может содержать заикающиеся слова:

"my wi wi windows10 is slow" => "my windows10 is slow"

Различные формы заикающихся слов в одной и той же группе повторов не учитываются:

"this is an ant antarctica does not have" => "this is an ant antarctica does not have"

Для нескольких непрерывных наборов заикающихся слов, следующих друг за другом, оставляйте только последнее исходное слово:

"what a be be be beauti beauti beautiful flower" => "what a beautiful flower"

Это не случай нескольких непрерывных наборов заикающихся слов сразу друг за другом:

"drink wat wat wa wa water" => "drink wat wat water"

Пустой ввод:

"" => ""

Больше случаев из комментариев:

"a ab abc" => "a ab abc"
"a ab ab abc" => "a abc"
"ab ab abc abcd" => "abc abcd"
"a a ab a able" => "ab a able"
"i have ave ave average" => "i have average"
"my wi wi windows 10 is cra cra crap" => "my windows 10 is crap"

Легко скопировать список вышеуказанных тестов:

"hello world",
"ope ope ope ope open the window",
"there is is is is something un un under the the the table",
"give me the the book",
"h h help m m m me",
"my nu nu number is 9 9 9 9876",
"my wi wi windows10 is slow",
"this is an ant antarctica does not have",
"what a be be be beauti beauti beautiful flower",
"drink wat wat wa wa water",
"",
"a ab abc",
"a ab ab abc",
"ab ab abc abcd",
"a a ab a able",
"i have ave ave average",
"my wi wi windows 10 is cra cra crap"
night2
источник
2
"drink wat wat wa wa water" => "drink wat wat water"действительно кажется, что правило должно применяться рекурсивно, чтобы это стало «пить воду»
Иона
2
@ Джона, если ты читаешь последний пункт в разделе Что такое заикающиеся слова? Я объяснил этот вопрос. «Ват Ват» - не заикающиеся слова для «ва», и мы исправляем только один раз, поэтому, как только мы получим «пить воду Ват ват», мы не исправляем снова, чтобы удалить вновь образованные заиканные слова. Но в обратном случае, как, например, «wa wa wat wat water», результатом будет «water», потому что «wa wa» - это заиканные слова для первых «wat», а «wat wat» также являются заиканными словами «water».
Night2
Хорошо, честно говоря, я просто говорил, что будет иметь смысл продолжать исправление, пока вы больше не сможете, но я вижу аргумент для сосредоточения на одной итерации.
Иона

Ответы:

6

C (gcc), 183 180 178 байт

f(s,t,u,T,e,r)char*s,*t,*u,*r;{for(;s=index(u=s,32);T>1&strpbrk(u,"aeiou")-1<s&&memmove(s=u,t-e,r-t-~e))for(e=++s-u,r=u+strlen(t=u),T=0;(t+=e)<r&!memcmp(u,t,e-1)&t[-1]==32;++T);}

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

Ну, C, конечно, не может конкурировать с краткостью регулярного выражения ...

Это особенно трудно читать, потому что я в итоге сложил всю функцию в одну вложенную пару forциклов (без тела!). Это делает порядок оценки совершенно непонятным - код в начале действительно выполняется последним.

Мой любимый трюк здесь strpbrk(u,"aeiou")-1<s. Это используется для проверки того, содержит ли повторяющееся слово гласные. uуказывает на начало повторяющегося слова и sуказывает на второе повторение слова; например:

"my nu nu number is 9 9 9 9876"
    ^  ^
    u  s

strpbrkзатем находит первый символ, "aeiou"который появляется после u. (В данном случае это 'u'сразу после.) Затем мы можем проверить, что это происходит раньше, sчтобы убедиться, что слово содержит гласный. Но есть небольшая проблема - strpbrkвозвращает NULL(т.е. 0), если во всей строке нет гласного. Чтобы это исправить, я просто вычитаю 1, который из-за переполнения превращается 0в 0xffffffffffffffff(на моей машине). Будучи максимальным значением указателя, оно определенно больше, чем s, что приводит к сбою проверки.

Вот немного более старая версия (до преобразования, которое запутало поток управления) с комментариями:

f(s,t,u,c,n,e)char*s,*t,*u,*e;{
    // set s to the position of the *next* check; u is the old position
    for(;s=index(u=s,32);) {
        // count the length of this word (incl. space); also fix s
        n=++s-u;
        // find the end of the string; assign temp pointer to start
        e=u+strlen(t=u);
        // count repetitions of the word
        for(c=0;                // number of repetitions
            (t+=n)              // advance temp pointer by length of word
            <e&&                // check that we haven't hit the end...
            !strncmp(u,t,n-1)&& // ...and the word matches...
            t[-1]==32;          // ...and the previous character was space
            ++c);               // if so, increment count
        // decide whether to remove stuttering
        c>1&&                    // count must be at least 2
        strpbrk(u,"aeiou")-1<s&& // word must contain a vowel
        // if so, move everything after the last occurrence back to the
        // beginning, and also reset s to u to start scanning from here again
        memmove(s=u,t-n,e-t+n+1);
    }
}

Спасибо @ user1475369 за 3 байта и @ceilingcat за 2 байта.

Дверная ручка
источник
-3 байта путем замены T>1&&strpbrkна T>1&strpbrk, r&&!strncmpс r&!strncmpи &&t[-1]на &t[-1].
girobuz
@ceilingcat Ваша ссылка не проходит некоторые тестовые случаи, но 2 из этих 3 оптимизаций работают; благодаря!
дверная ручка
Предлагаю bcmp()вместоmemcmp()
floorcat
4

Perl 5 (-p), 34 байта

На основании удаленного ответа Арно.

s/(\b(\w*[aeiou]\w*) )\1+(?=\2)//g

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

Grimmy
источник
Это производит "zab" для "za a ab". Я не думаю, что на этом входе должно быть обнаружено заикание.
рекурсивный
@ рекурсивное спасибо, исправлено.
Grimmy
2
Я посмотрел на контрольные примеры и разработал регулярное выражение, только чтобы найти его уже здесь. Естественно, это означает, что тривиальный порт Retina занимает 30 байтов.
Нил
3

05AB1E , 30 29 28 байт

-1 байт благодаря Кевину Круйссену

#Rγε®y¬©žMÃĀiнkĀDygαΘ+∍]R˜ðý

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

05AB1E, не имеющий регулярных выражений, определенно не выглядит лучшим инструментом для этой задачи. Тем не менее, ему как-то удается едва победить Retina.

#                     # split on spaces
 R                    # reverse the list of words
  γ                   # group consecutive identical words together

ε                   ] # for each group of words y:
 ®                    #  push the previous word on the stack (initially -1)
  y                   #  push another copy of y
   ¬                  #  push the first element without popping
    ©                 #  save the current word for the next loop
     žM               #  built-in constant aeiou
       ÃĀi          ] #  if the length of the intersection is non-zero:
           н          #   take the first element of y
            kĀ        #   0 if the previous word starts with this word, 1 otherwise
              D       #   duplicate
               yg     #   length of y (the number of consecutive identical words)
                 α    #   subtract the result of the startsWith check
                  Θ   #   05AB1E truthify (1 -> 1, anything else -> 0)
                   +  #   add the result of the startsWith check
                    ∍ #   set the length of y to that value
                      #  otherwise leave y unchanged

˜                     # flatten the modified list of groups of words
 R                    # reverse the list of words
  ðý                  # join with spaces
Grimmy
источник
1
Вы можете удалить gдо Ā. Trueify в стиле Python уже приведет 0к появлению пустых строк и 1непустых строк.
Кевин Круйссен
@KevinCruijssen хорошая находка!
Grimmy
1

Perl 6 , 45 байт

{S:g/<|w>(\S*<[aeiou]>\S*)\s$0+%%\s{}<?$0>//}

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

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

Джо Кинг
источник
1

Stax , 26 байт

å╬↓<▀.₧▀"╦n▐∞↨vß%ù:Qa3@=↔_

Запустите и отладьте его

Прямой порт из ответа Perl @ Grimy's. Stax способен сокращать литерал шаблона регулярных выражений, и у него есть постоянная гласных, которая может уменьшаться [aeiou].

рекурсивный
источник
1

Чисто , 184 байта

import StdEnv,Data.List,Text
$s=join[' '](f(group(split[' ']s)))
f[[a]:t]=[a:f t]
f[h=:[a:_]:t=:[[b:_]:_]]|intersect['aeiou']a==[]=h++f t|isPrefixOf a b=f t=if(h>[a,a])[a]h++f t
f[]=[]

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

Определяет $ :: [Char] -> [Char], что разбивает входную строку на пробелы и группирует идентичные элементы, которые затем свертываются помощником f :: [[[Char]]] -> [[Char]], соединяясь перед возвратом.

Οurous
источник