Réparer mes mots bégayés

12

Le bégaiement est un problème que beaucoup d'entre nous ont peut-être connu ou du moins vu. Bien que la plupart des logiciels de reconnaissance vocale connus aient de graves problèmes avec la parole bégayée, imaginons un logiciel qui comprend le bégaiement, mais ne peut pas les corriger et les écrit uniquement tels quels.

Un exemple de texte écrit par un tel logiciel peut ressembler à ceci: "veuillez faire attention ca ca" . Dans cet exemple, "attention" est le mot d'origine et "ca ca" sont les mots bégayés.

Défi

Écrivez un programme ou une fonction qui corrige les mots bégayés en les supprimant de l'entrée tout en conservant les mots d'origine. Par exemple, la version fixe de "s'il vous plaît soyez prudent" serait "s'il vous plaît soyez prudent" .

C'est le , la réponse la plus courte dans toutes les langues gagne!

Que sont les mots bégayés?

Le bégaiement a de nombreuses variantes différentes. Mais pour simplifier ce défi, nous allons le limiter aux règles suivantes:

  • Les mots bégayés peuvent être une partie incomplète ou la totalité du mot d'origine. Par «partie inachevée», je veux dire que le mot d'origine doit commencer exactement par le mot bégayé. Par exemple, "ope" et "open" peuvent tous deux être un mot bégayé pour "open" , mais "pen" ne peut pas en être un car "open" ne commence pas par "pen" .
  • Les mots bégayés doivent contenir au moins une des voyelles "aeiou" . Par exemple, "star" peut être un mot bégayé pour "start" car il contient "a" , mais "st" ne peut pas être un mot bégayé car il ne contient aucune des voyelles mentionnées.
  • Les mots bégayés ne peuvent apparaître qu'avant le mot d'origine et doivent être répétés au moins deux fois pour être valides (le mot d'origine ne compte pas dans les répétitions). Par exemple, "oo open" a des mots bégayés mais "o open o" ne le fait pas, car le "o" après le mot d'origine ne compte pas et "o" avant le mot d'origine n'est pas répété au moins deux fois. "go go go go go go" a cinq répétitions de mots bégayés avant le mot d'origine et est valide.
  • Un seul ensemble de mots bégayés répétés ne peut pas contenir de formes mixtes et les mots doivent être exactement comme les uns des autres. Par exemple, "op o op open" ne compte pas comme des mots bégayés. D'un autre côté, "o op op open" a des mots bégayés parce que le premier "o" est vu ici comme un tout autre mot et les deux "op" sont comptés comme des mots bégayés "open" .
  • Dans le cas de plusieurs ensembles valides de mots bégayés répétés juste après l'autre, seul le dernier mot original reste. Par exemple, dans "ooo op op op open" , la partie "oo o" est considérée comme des mots bégayés du premier "op" , ils doivent donc être supprimés, puis "op op op" est considéré comme des mots bégayés de "open" " et ils doivent également être supprimés, de sorte que seul " ouvert " sera laissé après la suppression des mots bégayés. Vous pouvez supposer que plusieurs ensembles valides de mots bégayés répétés ne se produisent que de gauche à droite, donc la fixation de "op op ooo open" entraînerait "op op open" (aka

Contribution

  • L'entrée est une chaîne d'une seule ligne contenant uniquement des lettres anglaises ASCII (az), des chiffres (0-9) et des caractères d'espacement. La casse des lettres n'est pas importante et vous pouvez décider d'accepter les minuscules ou les majuscules ou les deux, mais la casse doit rester la même et vous ne pouvez pas la modifier dans la sortie.
  • Vous pouvez utiliser une liste de lettres (comme ["l","i","s","t"," ","o","f"," ","l","e","t","t","e","r","s"]) au lieu de la chaîne, mais vous ne pouvez pas utiliser une liste de mots. Si votre langue a une structure d'entrée différente, utilisez-la. Le fait est que la saisie ne doit pas être séparée par des mots, donc le coût de la séparation des mots dans certaines langues pourrait en fait déclencher d'autres solutions créatives.
  • L'entrée peut contenir aucun, un ou plusieurs mots bégayés.
  • Les mots et ou les nombres sont séparés par un seul espace et l'entrée ne contiendra pas de doubles espaces les uns à côté des autres.

Production

  • Une chaîne ou une liste de lettres ou la structure appropriée dans votre langue avec tous les mots bégayés supprimés de l'entrée.
  • Les mots de sortie doivent être séparés par exactement un espace (identique à l'entrée).
  • Une nouvelle ligne ou un seul espace de début et de fin est autorisé.

Les failles standard sont interdites.

Cas de test

Pas de mots bégayés:

"hello world" => "hello world"

Une seule occurrence de mots bégayés répétés:

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

Plusieurs instances de mots bégayés répétés:

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

Pas de mots bégayés, pas assez répétés:

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

Pas de mots bégayés, pas de voyelles mentionnées:

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

Les chiffres ne sont pas des mots bégayés, ils n'ont aucune des voyelles mentionnées:

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

Mais un mot avec des voyelles et des chiffres peut avoir des mots bégayés:

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

Différentes formes de mots bégayés dans le même groupe de répétition ne sont pas comptées:

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

Pour plusieurs ensembles continus de mots bégayés l'un après l'autre, ne conservez que le dernier mot original:

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

Ce n'est pas le cas de plusieurs ensembles continus de mots bégayés l'un après l'autre:

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

Entrée vide:

"" => ""

Plus de cas de commentaires:

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

Une liste facile à copier des cas de test ci-dessus:

"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"
Nuit2
la source
2
"drink wat wat wa wa water" => "drink wat wat water"il semble vraiment que la règle devrait s'appliquer de manière récursive pour que cela devienne "boire de l'eau"
Jonah
2
@Jonah si vous lisez le dernier élément sous Quels sont les mots bégayés? J'ai expliqué cette question. "wat wat" ne sont pas des mots bégayés pour "wa" et nous ne réparons qu'une seule fois, donc une fois que nous obtenons "buvons de l'eau wat wat", nous ne corrigeons plus pour supprimer les mots bégayés nouvellement formés. Mais dans un cas inverse comme "wa wa wat wat water", le résultat sera "water" car "wa wa" sont des mots bégayés pour le premier "wat" et "wat wat" sont également des mots bégayés "water".
Night2
D'accord, je disais qu'il serait logique de continuer à corriger jusqu'à ce que vous ne puissiez plus, mais je peux voir l'argument pour se concentrer sur une seule itération également.
Jonah

Réponses:

6

C (gcc), 183 180 178 octets

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

Essayez-le en ligne!

Eh bien, C ne peut certainement pas rivaliser avec la brièveté de l'expression régulière ...

Celui-ci est particulièrement difficile à lire car j'ai fini par réduire toute la fonction en une seule paire imbriquée de for boucles (sans corps!). Cela rend l'ordre d'évaluation complètement bancal - le code près du début s'exécute en dernier.

Mon astuce préférée ici est strpbrk(u,"aeiou")-1<s. Ceci est utilisé pour vérifier si le mot répété contient des voyelles. upointe vers le début du mot répété et spointe vers la deuxième répétition du mot; par exemple:

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

strpbrktrouve ensuite le premier caractère "aeiou"qui apparaît après u. (Dans ce cas, c'est 'u'immédiatement après.) Ensuite, nous pouvons vérifier que cela vient avant spour vérifier que le mot contient une voyelle. Mais il y a un léger problème - strpbrkrenvoie NULL(c'est-à-dire 0) s'il n'y a pas de voyelle dans la chaîne entière. Pour résoudre ce problème, je soustrais simplement 1, qui se transforme 0en 0xffffffffffffffff(sur ma machine) en raison d'un débordement. Étant la valeur maximale d'un pointeur, elle est nettement supérieure às , ce qui entraîne l'échec de la vérification.

Voici une version légèrement plus ancienne (avant la transformation qui a brouillé le flux de contrôle) avec des commentaires:

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

Merci à @ user1475369 pour 3 octets et @ceilingcat pour 2 octets.

Poignée de porte
la source
-3 octets en remplaçant T>1&&strpbrkpar T>1&strpbrk, r&&!strncmppar r&!strncmpet &&t[-1]par &t[-1].
girobuz
@ceilingcat Votre lien échoue dans certains des cas de test, mais 2 de ces 3 optimisations fonctionnent; Merci!
Poignée de porte
Suggérer à la bcmp()place dememcmp()
plafondcat
4

Perl 5 (-p), 34 octets

Basé sur la réponse supprimée d'Arnauld.

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

Essayez-le en ligne!

Grimmy
la source
Cela produit "zab" pour "za a ab". Je ne pense pas qu'il devrait y avoir un bégaiement détecté dans cette entrée.
récursif
@recursive thanks, fixed.
Grimmy
2
J'ai regardé les cas de test et mis au point une expression rationnelle, pour la trouver déjà ici. Naturellement, cela signifie que le port Retina trivial est de 30 octets.
Neil
3

05AB1E , 30 29 28 octets

-1 octet grâce à Kevin Cruijssen

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

Essayez-le en ligne!

05AB1E, n'ayant aucune expression régulière, ne semble certainement pas être le meilleur outil pour cette tâche. Pourtant, il parvient à battre à peine 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
la source
1
Vous pouvez supprimer le gavant le Ā. La vérité de style Python entraînera déjà 0pour les chaînes vides et 1pour les chaînes non vides.
Kevin Cruijssen
@KevinCruijssen belle trouvaille!
Grimmy
1

Perl 6 , 45 octets

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

Essayez-le en ligne!

Une réponse regex simple qui remplace toutes les correspondances de bégaiements par la chaîne vide.

Jo King
la source
1

Stax , 26 octets

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

Exécuter et déboguer

Port direct depuis la réponse perl de @ Grimy. Stax est capable de réduire le littéral du motif d'expression régulière, et il a une constante de voyelles qui est capable de rétrécir [aeiou].

récursif
la source
1

Nettoyer , 184 octets

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

Essayez-le en ligne!

Définit $ :: [Char] -> [Char] , qui divise la chaîne d'entrée en espaces et regroupe des éléments identiques qui sont ensuite réduits par l'assistant f :: [[[Char]]] -> [[Char]], se rejoignant avant de revenir.

Οurous
la source