¡Eliminar plural (es) ambiguo (s)!

21

La programación es muy rígida. No puedes decirle a un programa que "muestre el recuento de bananas", tienes que decirle que lo haga print(bananas).

Pero cuando haces eso, terminas con un problema: no sabes cuántas bananas tienes de antemano, por lo que no sabes si usar un plural.

A veces, los programadores toman el camino vago. En lugar de verificar, simplemente imprimen there are X banana(s).

Pero eso es feo, por lo que necesitamos un programa para solucionar esto.

Los métodos)

Para eliminar los plurales ambiguos en una cadena, siga los siguientes pasos:

  1. Divide la cadena en espacios en una lista de palabras.

  2. Por cada palabra que termina con (s), haga lo siguiente:

    • Si la palabra precedente es a, an, 1o one, retire el (s)al final de la palabra.
    • De lo contrario, si la palabra es la primera palabra de la cadena o la palabra anterior no es a, an, 1o one, reemplazar el (s)al final de la palabra con s.
  3. Vuelva a unir la lista de palabras en una cadena, conservando el espacio en blanco original.

Ejemplo (s)

Tomemos una cuerda there's a banana(s) and three apple(s).

Primero, dividimos la cadena en una lista de palabras: ["there's", "a", "banana(s)", "and", "three", "apple(s)"]

Para el segundo paso, tomamos las dos palabras que terminan en (s): banana(s)y apple(s).

La palabra anterior banana(s)es a, así que eliminamos el (s), haciéndolo banana. La palabra anterior apple(s)es three, entonces cambiamos el (s)a s, así se convierte apples.

Ahora tenemos ["there's", "a", "banana", "and", "three", "apples"]. Uniéndonos a la lista nuevamente, lo conseguimos there's a banana and three apples. Este es nuestro resultado final.

Los desafios)

Cree un programa o función que tome una cadena ambigua en cualquier formato razonable y devuelva la versión no ambigua de esa cadena.

Puede suponer que la cadena no contiene nuevas líneas, pestañas o retornos de carro.

Olvidé especificar si dividir en grupos de espacios o espacios (es decir, si okay thendebería haber dos espacios ["okay", "then"]o ["okay", "", "then"]) al publicar el desafío, por lo que puede asumir cualquier forma de división.

Casos de prueba)

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

Tanteo

Como se trata de , ¡el envío con la menor cantidad de bytes gana!

LyricLy
fuente
Esta pregunta ha sido protegida .
LyricLy
¿Debería apple(s)ceder el caso de prueba apples? El desafío dice Otherwise, if the word is the first word in the string . . . replace the (s) at the end of the word with s.que noto que este caso cedió applesen la caja de arena para las primeras tres revisiones, pero cambió en la cuarta.
fireflame241
@ fireflame241 Al escribir el segundo borrador de las reglas, iba a hacerlo para que el inicio de la cadena no cambiara. Cambié esa regla más tarde, pero no el caso de prueba. Buena atrapada.
LyricLy
Sugerencia de caso de prueba: There's a single banana(s)-> There's a single bananas.
Jonathan Allan
1
@JonathanAllan No puedes. Agregaré algunos casos de prueba.
LyricLy

Respuestas:

6

Mathematica, 151 148 bytes

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}&

Explicación

j=" ";k=Except@j

Establecer jen un carácter de espacios en blanco. Establezca kel patrón "no j" (= carácter que no sea un espacio en blanco).

j<>j<>#<>j

Anteponga dos espacios en blanco y añada uno (s) a la entrada.

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

Para una (s) subcadena (s) que coinciden con el patrón:

  1. Un espacio en blanco, seguido de
  2. una subcadena de longitud cero o más larga que consta solo de caracteres que no son espacios en blanco (cuantificador) (llame a esto a), seguido de
  3. una subcadena de longitud uno o más larga que consta solo de caracteres de espacio en blanco (llame a esto s), seguido de
  4. una subcadena de longitud uno o más larga que consta solo de caracteres que no son espacios en blanco (palabra) (llame a esto w), seguido de
  5. la cadena "(s)", seguida de
  6. un espacio en blanco
Si [FreeQ [a, "a" | "an" | "1" | "one"], "s", ""]

Si ano es una de las palabras singulares, evalúe a "s", de lo contrario "".

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

Vuelva a colocar el patrón coincidente con j, a, s, w, If[FreeQ[a,"a"|"an"|"1"|"one"],"s",""], y junidas entre sí.

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

Tome de la posición 3 a la posición -2 (indexado 1; los índices negativos cuentan desde el final). Esto se debe a que agregamos tres espacios al principio.

JungHwan Min
fuente
3
¿Por qué no usar el incorporado para eliminar el plural-S?
Thomas Weller
5

Python 3 , 94 bytes

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

Pruébalo en línea!

-4 bytes gracias a i cri everytim (creo que esto es aceptable)

Hiperneutrino
fuente
@JonathanAllan Corregido, gracias.
HyperNeutrino
1
__import__no puede ser más corto ... Sí, es 4 bytes más corto como un habitual import re.
Totalmente humano el
@icrieverytim eh tienes razón (solo 3 bytes) gracias
HyperNeutrino
espere no aquí hay 94
totalmente humano
@icrieverytim ._. Oh bien. ¡Gracias!
HyperNeutrino
4

Retina , 53 bytes

(( |^)(a|an|1|one) [^ ]*)\(s\)( |$)
$1
\(s\)( |$)
s$1

Pruébalo en línea!

fireflame241
fuente
1
Esto elimina el espacio después de banana(s)en there's a banana(s) and three apple(s)- intente esta solución
Neil
Puede cambiar a|ana an?-1 byte
PunPun1000
4

Mathematica, 313 bytes

(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)&
J42161217
fuente
3

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

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

Haga coincidir cada uno (s)al final de la palabra, reemplácelo con !$1(1 o 0) esses.

Bajo
fuente
2

Pyth - 53 bytes

Sigue el algoritmo más o menos como es.

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

Pruébelo en línea aquí .

Maltysen
fuente
1
Falla en there are two banana(s) and one leprechaun(s)(dos espacios después de one). El espacio en blanco original se conserva, pero leprechaun(s)ignora el oneanterior.
LyricLy
1
@LyricLy no ha declarado esto explícitamente en el OP. Con dos espacios (usando (1) de la sección "método (s)" de "dividir la cadena en los espacios en una lista de palabras") en realidad hay una palabra vacía entre oneyleprechaun(s)
Jonathan Allan
2

Jalea ,  52 51  49 bytes

Jelly no tiene un átomo de expresiones regulares

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

Un programa completo que acepta una cadena (usando el formato Python si es multilínea o que contiene comillas) e imprime la salida.

Pruébalo en línea! o ver el conjunto de pruebas .

¿Cómo?

Ṫ - 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
Jonathan Allan
fuente
Tengo curiosidad por saber por qué lo usó como un enlace separado. ¿Esto impide eliminar el elemento de la lista original?
HyperNeutrino
No, necesito obtener la cola del par ... escribiendo un comentario de código, tal vez puedas ver un golf una vez que lo veas.
Jonathan Allan
Ah bien. ¡Gracias, intentaré detectar el golf una vez que haya un comentario (o antes)!
HyperNeutrino
Por lo tanto, los enlaces 1, 2 y 3 tienen cola, y el enlace 5 elige a qué llamar y lo usa Ŀpara hacerlo, pero no veo una forma corta de cola dentro del enlace 4, pero podría haberlo. ¡Incluso podría haber una manera de obtener la cola del enlace 4 allí también!
Jonathan Allan
@HyperNeutrino Creo que la Ŀcosa puede llamar al primer enlace, por eso es un enlace por sí solo.
Erik the Outgolfer
1

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

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

Pruébalo en línea!

Xcali
fuente
1
No en los casos de prueba, pero creo que esto falla a hel(s)lo.
Neil
Eso funciona correctamente según lo previsto en el caso de prueba. Está cerca del final de los casos de prueba en mi enlace TIO.
Xcali
Bueno, solo tendré que a hel(s)loagregarme a los casos de prueba, y luego tal vez arreglarás tu código ...
Neil
0

JavaScript (ES6), 88 87 bytes

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

Explicación próximamente.

XavCo7
fuente
1
puede reemplazar \scon `` de acuerdo con "Puede suponer que la cadena no contiene nuevas líneas, pestañas o retornos de carro".
SuperStormer
Falla en "this is a te (s) t". Puede solucionarlo agregando (\s|$)al final de la expresión regular.
Birjolaxew
También falla en "manzana (s)". Corregido en este TIO
Birjolaxew
Gracias @Birjolaxew, editaré los cambios cuando pueda ...
XavCo7
0

JavaScript (ES6), 84 bytes

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

Aquí hay una forma interesante de reorganizar la última parte, que lamentablemente es 2 bytes más larga:

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

JavaScript (SpiderMonkey) , 82 bytes

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

Pruébalo en línea!

Versión de 78 bytes (menos robusta)

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

Esta es una versión modificada de ETHproductions '(no tengo 50 rep.)

Explicación

  • /(\S+ +(\S+))\(s\)/g- el patrón real a buscar ( amount object(s))
  • (_,a)=>a- _es una captura de todas las variables, aes el(\S+ +(\S+))
  • "s"[+/^(1|one|an?)/i.test(a)]||""- en lugar de cortar la matriz, simplemente haga una matriz ficticia y obtenga el índice ( +/.../.testdevuelve un número)
    • debería "s"[+/^(1|one|an?)/i.test(a)]devolver undefined( trueo 1para la prueba) devolver""
Ephellon Dantzler
fuente