Supprimez les pluriels ambigus!


21

La programmation est très rigide. Vous ne pouvez pas dire à un programme de "sortir le nombre de bananes", vous devez le lui dire print(bananas).

Mais lorsque vous faites cela, vous vous retrouvez avec un problème: vous ne savez pas combien de bananes vous avez à l'avance, donc vous ne savez pas si vous devez utiliser un pluriel.

Parfois, les programmeurs vont paresseusement. Au lieu de vérifier, ils impriment simplement there are X banana(s).

Mais c'est moche, nous avons donc besoin d'un programme pour résoudre ce problème.

Les méthodes)

Pour supprimer les pluriels ambigus d'une chaîne, procédez comme suit:

  1. Divisez la chaîne des espaces en une liste de mots.

  2. Pour chaque mot qui se termine par (s), procédez comme suit:

    • Si le mot précédent est a, an, 1ou one, retirer la (s)fin du mot.
    • Dans le cas contraire, si le mot est le premier mot dans la chaîne ou le mot précédent est pas a, an, 1ou one, remplacer la (s)fin du mot s.
  3. Rejoins la liste des mots dans une chaîne, en préservant les espaces d'origine.

Exemples)

Prenons une chaîne there's a banana(s) and three apple(s).

Tout d'abord, nous avons divisé la chaîne en une liste de mots: ["there's", "a", "banana(s)", "and", "three", "apple(s)"]

Pour la deuxième étape, nous prenons les deux mots se terminant par (s): banana(s)et apple(s).

Le mot avant banana(s)est a, donc nous supprimons le (s), ce qui en fait banana. Le mot avant apple(s)est three, donc nous changeons le (s)en s, ainsi il devient apples.

Nous avons maintenant ["there's", "a", "banana", "and", "three", "apples"]. Rejouer la liste ensemble, nous obtenons there's a banana and three apples. Ceci est notre résultat final.

Les défis)

Créez un programme ou une fonction qui prend une chaîne ambiguë dans n'importe quel format raisonnable et renvoie la version non ambiguë de cette chaîne.

Vous pouvez supposer que la chaîne ne contient aucun retour à la ligne, tabulation ou retour chariot.

J'ai oublié de préciser si de diviser les groupes d'espaces ou des espaces ( à savoir si okay thenavec deux espaces doivent être ["okay", "then"]ou ["okay", "", "then"]) lors de la publication du défi, de sorte que vous pouvez prendre soit sous forme de division.

Cas de test

Input                                         -> Output
there are two banana(s) and one leprechaun(s) -> there are two bananas and one leprechaun
there's a banana(s) and three apple(s)        -> there's a banana and three apples
apple(s)                                      -> apples
one apple(s)                                  -> one apple
1 banana(s)                                   -> 1 banana
banana                                        -> banana
preserve    original      whitespace(s)       -> preserve    original      whitespaces
11 banana(s)                                  -> 11 bananas
an apple(s)                                   -> an apple
this is a te(s)t                              -> this is a te(s)t
I am a (s)tranger(s)                          -> I am a (s)tranger

Notation

Comme c'est du , la soumission avec le moins d'octets gagne!


Cette question a été mise en bac à sable .
LyricLy

Le scénario de apple(s)test devrait- il applesplutôt céder ? Le défi indique que Otherwise, if the word is the first word in the string . . . replace the (s) at the end of the word with s.je note que cette affaire a cédé applesen bac à sable pour les trois premières révisions mais a changé à la quatrième.
fireflame241

@ fireflame241 Lors de l'écriture du deuxième brouillon des règles, j'allais faire en sorte que le début de la chaîne reste inchangé. J'ai changé cette règle plus tard, mais pas le cas de test. Bonne prise.
LyricLy

Suggestion de cas de test: There's a single banana(s)-> There's a single bananas.
Jonathan Allan

1
@JonathanAllan Vous ne pouvez pas. J'ajouterai quelques cas de test.
LyricLy

Réponses:


6

Mathematica, 151 148 octets

StringReplace[j=" ";k=Except@j;j<>j<>#<>j,j~~a:k...~~s:j..~~w:k..~~"(s)"~~j:>{j,a,s,w,If[FreeQ[a,"a"|"an"|"1"|"one"],"s",""]}<>j]~StringTake~{3,-2}&

Explication

j=" ";k=Except@j

Défini jsur un ou plusieurs espaces. Définissez kle modèle "not j" (= caractère non blanc).

j<>j<>#<>j

Ajoutez deux espaces blancs et ajoutez un espace blanc à l'entrée.

j~~a:k...~~s:j..~~w:k..~~"(s)"~~j

Pour une ou des sous-chaînes correspondant au motif:

  1. Un ou plusieurs espaces, suivi de
  2. une sous-chaîne de longueur zéro ou plus longue composée uniquement de caractères non blancs (quantificateur) (appelez cela a), suivi de
  3. une sous-chaîne de longueur un ou plus longue composée uniquement de caractères d'espacement (appelez cela s), suivie de
  4. une sous-chaîne de longueur un ou plus longue composée uniquement de caractères non blancs (mot) (appelez cela w), suivi de
  5. la chaîne "(s)", suivie de
  6. un ou des espaces
Si [FreeQ [a, "a" | "an" | "1" | "one"], "s", ""]

Si an'est pas l'un des mots singuliers, évaluez à "s", sinon "".

StringReplace[..., ... :>{j,a,s,w,If[FreeQ[a,"a"|"an"|"1"|"one"],"s",""]}<>j]

Remplacer la configuration d'adaptation avec j, a, s, w, If[FreeQ[a,"a"|"an"|"1"|"one"],"s",""], et jreliés entre eux.

... ~StringTake~{3,-2}

Passer de la position 3 à la position -2 (1 indexé; les indices négatifs comptent à partir de la fin). C'est parce que nous avons ajouté trois espaces au début.


3
Pourquoi ne pas utiliser la fonction intégrée pour supprimer le pluriel-S?
Thomas Weller

5

Python 3 , 94 octets

lambda s,r=re.sub:r(r"\(s\)( |$)","s",r(r"\b(an?|1|one)(\s+)(.+)\(s\)",r"\1\2\3",s))
import re

Essayez-le en ligne!

-4 octets grâce à i cri everytim (je pense que c'est acceptable)


@JonathanAllan Fixed, merci.
HyperNeutrino

1
__import__ne peut pas être plus court ... Ouais, c'est 4 octets plus court comme un régulier import re.
2017 totalement humain

@icrieverytim hein, vous avez raison (seulement 3 octets cependant) merci
HyperNeutrino


@icrieverytim ._. Oh sympa. Merci!
HyperNeutrino


4

Mathematica, 313 octets

(Table[If[StringLength@z[[i]]>3&&StringTake[z[[i]],-3]=="(s)",z[[i]]=StringDrop[z[[i]],-3];t=1;While[z[[i-t]]=="",t++];If[FreeQ[{"a","an","1","one"},z[[i-t]]],z[[i]]=z[[i]]<>"s"]],{i,2,Length[z=StringSplit[#," "]]}];If[StringTake[z[[1]],-3]=="(s)",z[[1]]=StringDrop[z[[1]],-3];z[[1]]=z[[1]]<>"s"];StringRiffle@z)&

3

Perl 5, 43 + 1 (-p) = 44 octets

s/\b((one|1|an?) +)?\S+\K\(s\)\B/"s"x!$1/ge

Correspond à chaque (s)fin de mot, remplacez-le par !$1(1 ou 0) esses.


2

Pyth - 53 octets

Suit l'algorithme à peu près tel qu'il est.

K+kczdjdt.e?q"(s)"gb_2+<b_3*\s!}@Ktk[\a"an""one"\1)bK

Essayez-le en ligne ici .


1
Échoue there are two banana(s) and one leprechaun(s)(deux espaces après le one). L'espace d'origine est conservé, mais leprechaun(s)ignore le oneprécédent.
LyricLy

1
@LyricLy vous ne l'avez pas explicitement indiqué dans le PO. Avec deux espaces (en utilisant (1) de votre section "méthode (s)" de "diviser la chaîne sur les espaces en une liste de mots"), il y a en fait un mot vide entre oneetleprechaun(s)
Jonathan Allan

2

Gelée ,  52 51  49 octets

Jelly n'a pas d'atome de regex (s)

Ṫ
Ñ;”s
Ṫḣ-3
UṪw“)s(”⁼1
“µḣ⁴µuʠg*»ḲċḢ‘×Ç‘
⁶;ḲÇĿ2ƤK

Un programme complet acceptant une chaîne (utilisant le formatage Python si multiligne ou contenant des guillemets) et imprimant la sortie.

Essayez-le en ligne! ou voir la suite de tests .

Comment?

Ṫ - Link 1, tail: two words (list of lists)
Ṫ - tail

Ñ;”s - Link 2, tail and replace last three chars with an 's': two words (list of lists)
Ñ    - call the next link (3) as a monad
  ”s - literal 's'
 ;   - concatenate

Ṫḣ-3 - Link 3, tail and remove the last three chars: two words (list of lists)
Ṫ    - tail
  -3 - literal minus three
 ḣ   - head from index (1-indexed and modular)

UṪw“)s(”⁼1 - Link 4, tail ends with "(s)"?: two words (list of lists)
U          - upend (reverse each word)
 Ṫ         - tail
   “)s(”   - literal [')', 's', '('] - that is "(s)" reversed
  w        - index of first sublist equal to that or 0 if not found
         1 - literal one
        ⁼  - equal?

“µḣ⁴µuʠg*»ḲċḢ‘×Ç‘ - Link 5, categorise: two words (list of lists)
“µḣ⁴µuʠg*»        - compression of string "a 1" + word " an" + word " one"
          Ḳ       - split on spaces = ["a", "1", "an", "one"]
            Ḣ     - head (the first word)
           ċ      - count occurrences (of head in the list - either 0 or 1)
             ‘    - increment
               Ç  - call the last link (4) as a monad - i.e. f(two words)
              ×   - multiply
                ‘ - increment - so we have: 1 for ["1", "blah"],
                  -             2 for ["blah", "blah(s)"] or 3 for ["1", "blah(s)"]

⁶;ḲÇĿ2ƤK - Main link: list of characters, the string
⁶        - literal space character
 ;       - concatenate (place a space at the beginning as we want to inspect pairs)
  Ḳ      - split on spaces (giving an empty list at the start)
     2Ƥ  - for all infixes of length two:
    Ŀ    -   call the link at the given index as a monad:
   Ç     -     call the last link (5) as a monad
       K - join the result with spaces
         - implicit print

Je suis curieux de savoir pourquoi vous avez utilisé un lien distinct. Cela empêche-t-il de supprimer l'élément de la liste d'origine?
HyperNeutrino

Non, je dois obtenir la queue de la paire ... rédiger un commentaire de code, peut-être que vous pourrez repérer un golf une fois que vous aurez vu cela.
Jonathan Allan

Ah ok. Merci, je vais essayer de repérer le golf une fois qu'il y aura un commentaire (ou avant)!
HyperNeutrino

Ainsi, les liens 1, 2 et 3 sont tous de queue, et le lien 5 choisit lequel appeler et utilise Ŀpour le faire, mais je ne vois pas de moyen court de suivre à l'intérieur du lien 4, mais il pourrait y en avoir. Il pourrait même y avoir un moyen d'y mettre la queue du lien 4!
Jonathan Allan

@HyperNeutrino Je pense que le Ŀbidule peut appeler le premier lien, c'est pourquoi c'est un lien à lui tout seul.
Erik the Outgolfer du 1er


1

Perl 5 , 56 + 1 ( -p) = 57 octets

s/\b(an?|1|one) +\S+\K\(s\)(?= |$)//g;s/\(s\)( |$)/s$1/g

Essayez-le en ligne!


1
Pas sur les cas de test, mais je pense que cela échoue a hel(s)lo.
Neil

Cela fonctionne correctement comme prévu dans le cas de test. C'est près du bas des cas de test dans mon lien TIO.
Xcali

Eh bien, je vais juste devoir être a hel(s)loajouté aux cas de test, et puis peut-être que vous corrigerez votre code ...
Neil

0

JavaScript (ES6), 88 87 octets

a=>a.replace(/(\S+)( +)(\S+)\(s\)/g,(m,f,s,w)=>f+s+w+(/^(a|an|1|one)$/.exec(f)?'':'s'))

Explication à venir.


1
vous pouvez remplacer \spar `` selon "Vous pouvez supposer que la chaîne ne contient aucun retour à la ligne, tabulation ou retour chariot."
SuperStormer

Échoue sur "c'est un te (s) t". Vous pouvez résoudre ce problème en ajoutant (\s|$)à la fin de l'expression régulière.
Birjolaxew

Échoue également sur "pomme (s)". Corrigé dans ce TIO
Birjolaxew

Merci @Birjolaxew, éditerai les changements quand je pourrai ...
XavCo7

0

JavaScript (ES6), 84 octets

s=>s.replace(/((^|\S+ +)\S+)\(s\)(?!\S)/g,(_,a)=>a+(/^(1|an?|one) /.test(a)?'':'s'))

Voici une façon intéressante de réorganiser la dernière partie, qui est malheureusement de 2 octets de plus:

s=>s.replace(/((^|\S+ +)\S+)\(s\)(?!\S)/g,(_,a)=>a+'s'.slice(/^(1|an?|one) /.test(a)))

0

JavaScript (SpiderMonkey) , 82 octets

s=s.replace(/(\S+ +(\S+))\(s\)\B/g,(_,a)=>a+("s"[+/^(1|one|an?)\b/i.test(a)]||""))

Essayez-le en ligne!

Version 78 octets (moins robuste)

s=s.replace(/(\S+ +(\S*))\(s\)/g,(_,a)=>a+("s"[+/^(1|one|an?)/i.test(a)]||""))

Ceci est une version modifiée de ETHproductions '(je n'ai pas 50 rep.)

Explication

  • /(\S+ +(\S+))\(s\)/g- le motif réel à rechercher ( amount object(s))
  • (_,a)=>a- _est une variable catch all, aest la(\S+ +(\S+))
  • "s"[+/^(1|one|an?)/i.test(a)]||""- au lieu de découper le tableau, créez simplement un tableau factice et obtenez l'index ( +/.../.testretourne un nombre)
    • devrait "s"[+/^(1|one|an?)/i.test(a)]retourner undefined( true, ou 1pour le test)""
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.