Corrija minhas palavras gagas

12

A gagueira é um problema que muitos de nós podem ter experimentado ou pelo menos visto. Embora a maioria dos softwares famosos de reconhecimento de fala tenha sérios problemas com a fala gaguejada, vamos imaginar um software que entenda a gagueira, mas não possa consertá-los e apenas os escreva como estão.

Um exemplo de texto escrito por esse software pode ser assim: "por favor, tenha cuidado" . Neste exemplo, "cuidado" é a palavra original e "ca ca" são as palavras gagas.

Desafio

Escreva um programa ou função que corrija palavras gaguejadas, removendo-as da entrada e mantendo as palavras originais. Por exemplo, a versão fixa de "por favor, tenha cuidado" seria "por favor, cuidado" .

Este é o , a resposta mais curta em todos os idiomas vence!

O que são palavras gagas?

A gagueira tem muitas variações diferentes. Mas, para simplificar esse desafio, vamos limitá-lo às seguintes regras:

  • Palavras gaguejadas podem ser uma parte incompleta ou toda a palavra original. Por "parte incompleta", quero dizer que a palavra original deve começar exatamente com a palavra gaguejada. Por exemplo, "ope" e "open" podem ser palavras gaguejadas para "open" , mas "pen" não pode ser uma, já que "open" não começa com "pen" .
  • Palavras gagas devem conter pelo menos uma das vogais "aeiou" . Por exemplo, "estrela" pode ser uma palavra gaguejada para "start" , pois contém "a" , mas "st" não pode ser uma palavra gaguejada, pois não contém nenhuma das vogais mencionadas.
  • Palavras gaguejadas só podem aparecer antes da palavra original e devem ser repetidas pelo menos duas vezes para serem válidas (a palavra original não conta nas repetições). Por exemplo, "oo open" gaguejou as palavras, mas "o open o" não, porque o "o" após a palavra original não conta e "o" antes da palavra original não ser repetida pelo menos duas vezes. "vai vai vai vai vai vai" tem cinco repetições de palavras gagas antes da palavra original e é válido.
  • Um único conjunto de palavras repetidas e gaguejadas não pode conter formas mistas e as palavras devem ser exatamente iguais umas às outras. Por exemplo, "op o op open" não conta como palavras gagas. Por outro lado, "o op op open" gaguejou palavras porque o primeiro "o" é visto como uma palavra totalmente diferente aqui e os dois "op" s são contados como palavras gaguejadas de "open" .
  • No caso de vários conjuntos válidos de palavras gaguejadas repetidas logo após o outro, apenas a última palavra original permanece. Por exemplo, em "ooo op op op open" , a parte "oo o" é vista como palavras gagas do primeiro "op" , portanto elas devem ser removidas e, em seguida, "op op op" é vista como palavras gagas de "open " e eles também devem ser removidos, para que apenas o " aberto " seja deixado após a remoção das palavras gagas. Você pode supor que vários conjuntos válidos de palavras gaguejadas repetidas só acontecem da esquerda para a direita, portanto, corrigir "op op ooo open" resultaria em "op op open" (também conhecido como

Entrada

  • A entrada é uma sequência de linhas única contendo apenas letras em inglês ASCII (az), dígitos (0-9) e caracteres de espaço. A letra maiúscula não é importante e você pode aceitar letras minúsculas ou maiúsculas ou ambas, mas a letra maiúscula deve permanecer a mesma e você não pode alterá-la na saída.
  • Você pode usar uma lista de letras (como ["l","i","s","t"," ","o","f"," ","l","e","t","t","e","r","s"]) em vez da sequência, mas não pode usar uma lista de palavras. Se o seu idioma tiver uma estrutura de entrada diferente, use-a. O ponto é que a entrada não deve ser separada por palavras; portanto, o custo da separação de palavras em alguns idiomas pode realmente desencadear outras soluções criativas.
  • A entrada pode conter nenhuma, uma ou várias palavras gaguejadas.
  • Palavras e ou números são separados por um único espaço e a entrada não conterá espaços duplos um ao lado do outro.

Resultado

  • Uma string ou uma lista de letras ou a estrutura apropriada no seu idioma com todas as palavras gagas removidas da entrada.
  • As palavras de saída devem ser separadas por exatamente um espaço (igual à entrada).
  • Nova linha ou espaço à esquerda e à direita são permitidos.

As brechas padrão são proibidas.

Casos de teste

Nenhuma palavra gaguejada:

"hello world" => "hello world"

Uma única instância de repetidas palavras gagas:

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

Várias instâncias de palavras gagas repetidas:

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

Nenhuma palavra gaguejada, nem repetida o suficiente:

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

Nenhuma palavra gaguejada, não possui nenhuma das vogais mencionadas:

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

Os números não são palavras gagas, eles não têm nenhuma das vogais mencionadas:

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

Mas uma palavra com vogais e números pode ter palavras gagas:

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

Diferentes formas de palavras gaguejadas no mesmo grupo de repetição não são contadas:

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

Para vários conjuntos contínuos de palavras gaguejadas, um após o outro, mantenha apenas a última palavra original:

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

Este não é um caso de vários conjuntos contínuos de palavras gaguejadas logo após o outro:

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

Entrada vazia:

"" => ""

Mais casos de comentários:

"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"

Uma lista fácil de copiar dos casos de teste acima:

"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
fonte
2
"drink wat wat wa wa water" => "drink wat wat water"realmente parece que a regra deve ser aplicada de forma recursiva para que isso se torna "água bebida"
Jonah
2
@ Jonah, se você leu o último item em O que são palavras gagas? Eu expliquei esse assunto. "wat wat" não são palavras gaguejadas para "wa" e corrigimos apenas uma vez; assim que obtemos "beber água wat wat", não corrigimos novamente para remover as palavras gagas recém-formadas. Porém, em um caso inverso, como "wa wa wat wat water", o resultado será "water" porque "wa wa" são palavras gaguejadas para o primeiro "wat" e "wat wat" também são palavras gaguejadas de "água".
night2
Tudo bem, eu estava dizendo que faria sentido continuar corrigindo até que você não pudesse mais, mas também vejo o argumento para focar em uma única iteração.
Jonas

Respostas:

6

C (gcc), 183 180 178 bytes

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

Experimente online!

Bem, C certamente não pode competir com a brevidade do regex ...

É particularmente difícil de ler, porque acabei colapsando a função inteira em um único par de forloops aninhados (sem corpo!). Isso faz com que a ordem de avaliação fique instável - o código próximo ao início é executado por último.

Meu truque favorito aqui é strpbrk(u,"aeiou")-1<s. Isso é usado para verificar se a palavra repetida contém vogais. uaponta para o início da palavra repetida e saponta para a segunda repetição da palavra; por exemplo:

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

strpbrkdepois encontra o primeiro caractere "aeiou"que aparece depois u. (Nesse caso, é o 'u'imediatamente seguinte.) Em seguida, podemos verificar se isso vem antes spara verificar se a palavra contém uma vogal. Mas há um pequeno problema - strpbrkretorna NULL(ou seja 0) se não houver vogal em toda a cadeia. Para corrigir isso, basta subtrair 1, que se 0transforma 0xffffffffffffffff(na minha máquina) devido ao estouro. Sendo o valor máximo de um ponteiro, este é decididamente maior que s, causando uma falha na verificação.

Aqui está uma versão um pouco mais antiga (antes da transformação que atrapalhava o fluxo de controle) com comentários:

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

Obrigado a @ user1475369 por 3 bytes e a @ceilingcat por 2 bytes.

Maçaneta da porta
fonte
-3 bytes substituindo T>1&&strpbrkpor T>1&strpbrk, r&&!strncmpcom r&!strncmpe &&t[-1]com &t[-1].
precisa saber é o seguinte
@ceilingcat Seu link falha em alguns dos casos de teste, mas 2 dessas 3 otimizações funcionam; obrigado!
Maçaneta
Sugerir em bcmp()vez dememcmp()
ceilingcat 30/09/19
4

Perl 5 (-p), 34 bytes

Com base na resposta excluída de Arnauld.

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

Experimente online!

Grimmy
fonte
Isso produz "zab" para "za a ab". Eu não acho que deveria haver uma gagueira detectada nessa entrada.
recursivo
@ obrigado recursivo, fixo.
Grimmy
2
Eu olhei para os casos de teste e criei uma regex, apenas para encontrá-la aqui. Naturalmente, isso significa que a porta Retina trivial é de 30 bytes.
Neil
3

05AB1E , 30 29 28 bytes

-1 byte graças a Kevin Cruijssen

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

Experimente online!

05AB1E, sem regexes, definitivamente não parece a melhor ferramenta para esta tarefa. Ainda assim, ele de alguma forma consegue apenas vencer a 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
fonte
1
Você pode remover o gantes do Ā. O trueify no estilo Python já resultará em 0strings vazias e em strings 1não vazias.
Kevin Cruijssen 23/09/19
@KevinCruijssen nice find!
Grimmy
1

Perl 6 , 45 bytes

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

Experimente online!

Uma resposta simples de regex que substitui todas as correspondências de gagueiras pela string vazia.

Brincadeira
fonte
1

Stax , 26 bytes

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

Execute e depure

Porta direta da resposta perl do @ Grimy. Stax é capaz de encolher literalmente o padrão regex, e possui uma constante de vogais que é capaz de encolher [aeiou].

recursivo
fonte
1

Limpo , 184 bytes

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[]=[]

Experimente online!

Define $ :: [Char] -> [Char], que divide a sequência de entrada em espaços e agrupa elementos idênticos que são recolhidos pelo auxiliar f :: [[[Char]]] -> [[Char]], juntando-se antes de retornar.

Furioso
fonte