Repariere meine gestotterten Worte

12

Stottern ist ein Problem, das viele von uns vielleicht erlebt oder zumindest gesehen haben. Obwohl die meisten bekannten Spracherkennungssoftware schwerwiegende Probleme mit stotterndem Sprechen haben, stellen wir uns eine Software vor, die Stottern versteht, diese aber nicht beheben kann und sie nur so schreibt, wie sie ist.

Ein Beispieltext, der von einer solchen Software geschrieben wurde, kann folgendermaßen lauten: "Bitte seien Sie vorsichtig" . In diesem Beispiel ist "vorsichtig" das ursprüngliche Wort und "ca ca" die gestotterten Wörter.

Herausforderung

Schreiben Sie ein Programm oder eine Funktion, die stotternde Wörter korrigiert, indem Sie sie aus der Eingabe entfernen und dabei die ursprünglichen Wörter beibehalten. Zum Beispiel fester Version von „bitte ca ca vorsichtig sein , “ wäre „bitte vorsichtig sein“ .

Dies ist , kürzeste Antwort in jeder Sprache gewinnt!

Was sind gestotterte Wörter?

Stottern hat viele verschiedene Variationen. Der Einfachheit halber werden wir diese Herausforderung auf die folgenden Regeln beschränken:

  • Gestotterte Wörter können ein unvollständiger Teil oder das Ganze des ursprünglichen Wortes sein. Mit "unvollständiger Teil" meine ich, dass das ursprüngliche Wort genau mit dem gestotterten Wort beginnen sollte. Zum Beispiel können "ope" und "open" beide ein gestottertes Wort für "open" sein , aber "pen" kann kein Wort sein, da "open" nicht mit "pen" beginnt .
  • Gestotterte Wörter müssen mindestens einen der "aeiou" -Vokale enthalten. Zum Beispiel kann "Stern" ein gestottertes Wort für "Start" sein, da es "a" enthält , aber "st" kann kein gestottertes Wort sein, da es keinen der genannten Vokale enthält.
  • Gestotterte Wörter können nur vor dem ursprünglichen Wort erscheinen und sollten mindestens zweimal wiederholt werden, um gültig zu sein (das ursprüngliche Wort zählt in den Wiederholungen nicht). Zum Beispiel hat "oo open" Wörter gestottert, "o open o" jedoch nicht, da das "o" nach dem ursprünglichen Wort nicht zählt und "o" vor dem ursprünglichen Wort nicht mindestens zweimal wiederholt wird. "go go go go go go" enthält fünf Wiederholungen gestotterter Wörter vor dem ursprünglichen Wort und ist gültig.
  • Ein einzelner Satz wiederholter gestotterter Wörter kann keine gemischten Formen enthalten, und die Wörter sollten genau gleich sein. Zum Beispiel zählt "op o op open" nicht als gestotterte Wörter. Andererseits hat "o op op open" Wörter gestottert, weil das erste "o" hier als ein ganz anderes Wort gesehen wird und die beiden "op" als gestotterte Wörter von "open" gezählt werden .
  • Bei mehreren gültigen Sätzen wiederholter gestotterter Wörter direkt nacheinander bleibt nur das letzte Originalwort übrig. Zum Beispiel wird in "ooo op op op open" der Teil "oo o" als gestotterte Wörter des ersten "op" angesehen , daher sollten sie entfernt werden, und dann wird "op op op" als gestotterte Wörter von "open" angesehen " und sie sollten auch entfernt werden, so dass nach dem Entfernen gestotterter Wörter nur das " offene " übrig bleibt. Sie können , dass mehrere gültigen Sätze von wiederholten stotterte Worten annehmen nur von links nach rechts passieren, so Fixierung „op op ooo offen“ in Folge hätte „op op open“ (auch bekannt als

Eingang

  • Die Eingabe ist eine einzeilige Zeichenfolge, die nur englische ASCII-Buchstaben (az), Ziffern (0-9) und Leerzeichen enthält. Die Groß- und Kleinschreibung ist nicht wichtig und Sie können entscheiden, ob Sie Klein- oder Großbuchstaben oder beide akzeptieren möchten. Die Groß- und Kleinschreibung sollte jedoch gleich bleiben und Sie können sie in der Ausgabe nicht ändern.
  • Sie können ["l","i","s","t"," ","o","f"," ","l","e","t","t","e","r","s"]anstelle der Zeichenfolge eine Liste mit Buchstaben (wie ) verwenden, aber keine Liste mit Wörtern. Wenn Ihre Sprache eine andere Eingabestruktur hat, verwenden Sie diese. Der Punkt ist, dass Eingaben nicht durch Wörter getrennt werden sollten, sodass die Kosten für die Trennung von Wörtern in einigen Sprachen möglicherweise andere kreative Lösungen auslösen.
  • Die Eingabe enthält möglicherweise kein, ein oder mehrere gestotterte Wörter.
  • Wörter und / oder Zahlen werden durch ein einzelnes Leerzeichen getrennt, und die Eingabe enthält keine doppelten Leerzeichen direkt nebeneinander.

Ausgabe

  • Eine Zeichenfolge oder eine Liste von Buchstaben oder die entsprechende Struktur in Ihrer Sprache, wobei alle gestotterten Wörter aus der Eingabe entfernt wurden.
  • Ausgabewörter sollten durch genau ein Leerzeichen getrennt sein (wie Eingabe).
  • Einzelne führende und nachfolgende Zeilenumbrüche oder Leerzeichen sind zulässig.

Standardlücken sind verboten.

Testfälle

Keine gestotterten Worte:

"hello world" => "hello world"

Eine einzelne Instanz wiederholter stotternder Wörter:

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

Mehrere Fälle von wiederholten stotternden Wörtern:

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

Keine gestotterten Worte, nicht genug wiederholt:

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

Keine gestotterten Wörter, haben Sie keinen der genannten Vokale:

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

Zahlen sind keine gestotterten Wörter, sie haben keinen der genannten Vokale:

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

Aber ein Wort mit Vokalen und Zahlen kann stotternde Wörter haben:

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

Verschiedene Formen von gestotterten Wörtern in derselben Wiederholungsgruppe werden nicht gezählt:

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

Behalten Sie für mehrere fortlaufende Sätze gestotterter Wörter direkt nacheinander nur das letzte Originalwort bei:

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

Dies ist kein Fall von mehreren fortlaufenden Sätzen gestotterter Wörter direkt nacheinander:

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

Leere Eingabe:

"" => ""

Weitere Fälle aus Kommentaren:

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

Eine einfach zu kopierende Liste der oben genannten Testfälle:

"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"
Nacht2
quelle
2
"drink wat wat wa wa water" => "drink wat wat water"Es scheint wirklich so, als ob die Regel rekursiv gelten sollte, damit dies zu "Trinkwasser" wird
Jonah,
2
@ Jonah, wenn Sie den letzten Artikel unter Was sind gestotterte Wörter? Ich habe diese Angelegenheit erklärt. "wat wat" sind keine gestotterten Wörter für "wa" und wir korrigieren nur einmal. Sobald wir also "trinken wat wat water" erhalten, korrigieren wir nicht erneut, um neu gebildete gestotterte Wörter zu entfernen. In einem umgekehrten Fall wie "wa wa wat wat water" ist das Ergebnis "water", da "wa wa" gestotterte Wörter für das erste "wat" sind und "wat wat" auch gestotterte Wörter von "water" sind.
Night2
Okay, fair genug, ich habe nur gesagt, es wäre sinnvoll, so lange zu reparieren, bis Sie nicht mehr konnten, aber ich kann das Argument sehen, sich auch auf eine einzelne Iteration zu konzentrieren.
Jonah

Antworten:

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

Probieren Sie es online aus!

Nun, C kann mit der Kürze des regulären Ausdrucks sicherlich nicht mithalten ...

Dies ist besonders schwer zu lesen, da ich die gesamte Funktion in einem einzigen verschachtelten Paar von forSchleifen (ohne Körper!) Zusammengelegt habe. Das macht die Auswertungsreihenfolge ganz wackelig - der Code am Anfang wird tatsächlich zuletzt ausgeführt.

Mein Lieblingstrick hier ist strpbrk(u,"aeiou")-1<s. Dies wird verwendet, um zu überprüfen, ob das wiederholte Wort Vokale enthält. uzeigt auf den Anfang des wiederholten Wortes und szeigt auf die zweite Wiederholung des Wortes; beispielsweise:

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

strpbrkfindet dann das erste Zeichen "aeiou", das danach erscheint u. (In diesem Fall ist es das 'u'unmittelbar danach.) Dann können wir überprüfen, ob dies vorher kommt s, um zu überprüfen, ob das Wort einen Vokal enthält. Aber es gibt ein kleines Problem - gibt strpbrkzurück NULL(dh 0), wenn die gesamte Zeichenfolge keinen Vokal enthält. Um dies zu beheben, subtrahiere ich einfach 1, die sich aufgrund eines Überlaufs 0in 0xffffffffffffffff(auf meinem Computer) verwandelt . Als Maximalwert eines Zeigers ist dieser Wert deutlich größer als s, was dazu führt, dass die Prüfung fehlschlägt.

Hier ist eine etwas ältere Version (vor der Transformation, die den Kontrollfluss durcheinander brachte) mit Kommentaren:

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

Vielen Dank an @ user1475369 für 3 Bytes und @ceilingcat für 2 Bytes.

Türknauf
quelle
-3 Bytes durch Ersetzen T>1&&strpbrkdurch T>1&strpbrk, r&&!strncmpmit r&!strncmpund &&t[-1]mit &t[-1].
Girobuz
@ceilingcat Ihr Link schlägt in einigen Testfällen fehl, aber 2 dieser 3 Optimierungen funktionieren. Vielen Dank!
Türknauf
Schlagen Sie bcmp()stattmemcmp()
Deckenkatze
4

Perl 5 (-p), 34 Bytes

Basierend auf Arnauld's gelöschter Antwort.

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

Probieren Sie es online aus!

Grimmy
quelle
Dies erzeugt "zab" für "za a ab". Ich denke nicht, dass in dieser Eingabe ein Ruckeln festgestellt werden sollte.
rekursiv
@rekursiv danke, behoben.
Grimmy
2
Ich habe mir die Testfälle angesehen und einen regulären Ausdruck entwickelt, nur um ihn bereits hier zu finden. Dies bedeutet natürlich, dass der triviale Retina-Port 30 Bytes beträgt.
Neil
3

05AB1E , 30 29 28 Bytes

-1 Byte dank Kevin Cruijssen

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

Probieren Sie es online aus!

05AB1E, das keine regulären Ausdrücke hat, scheint definitiv nicht das beste Werkzeug für diese Aufgabe zu sein. Trotzdem schafft es es irgendwie, Retina kaum zu schlagen.

#                     # 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
quelle
1
Sie können das gvor dem entfernen Ā. Python-artige Wahrheitsfindung führt bereits 0zu leeren und 1nicht leeren Zeichenfolgen.
Kevin Cruijssen
@ KevinCruijssen schöner Fund!
Grimmy
1

Perl 6 , 45 Bytes

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

Probieren Sie es online aus!

Eine einfache Regex-Antwort, die alle Übereinstimmungen von Stottern durch die leere Zeichenfolge ersetzt.

Scherzen
quelle
1

Stax , 26 Bytes

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

Führen Sie es aus und debuggen Sie es

Direkter Port von @ Grimys Perl-Antwort. Stax kann das Regex-Musterliteral verkleinern und hat eine Vokalkonstante, die verkleinert werden kann [aeiou].

rekursiv
quelle
1

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

Probieren Sie es online aus!

Definiert $ :: [Char] -> [Char], wodurch die Eingabezeichenfolge auf Leerzeichen aufgeteilt und identische Elemente gruppiert werden, die dann vom Helfer reduziert werden f :: [[[Char]]] -> [[Char]], bevor sie zurückkehren.

Οurous
quelle