Remova plural (es) ambíguo (s)!

21

A programação é muito rígida. Você não pode dizer a um programa para "gerar a contagem de bananas", é necessário dizer a ele print(bananas).

Mas quando você faz isso, acaba com um problema: você não sabe quantas bananas você tem antes, então não sabe se deve usar um plural.

Às vezes, os programadores seguem o caminho preguiçoso. Em vez de verificar, eles apenas imprimem there are X banana(s).

Mas isso é feio, então precisamos de um programa para corrigir isso.

Os métodos)

Para remover os plurais ambíguos em uma seqüência de caracteres, siga as seguintes etapas:

  1. Divida a string nos espaços em uma lista de palavras.

  2. Para cada palavra que termina com (s), faça o seguinte:

    • Se a palavra anterior é a, an, 1ou one, remover o (s)no fim da palavra.
    • Caso contrário, se a palavra é a primeira palavra na cadeia ou a palavra anterior não é a, an, 1ou one, substitua o (s)no final da palavra com s.
  3. Junte a lista de palavras novamente em uma sequência, preservando o espaço em branco original.

Exemplos)

Vamos pegar uma corda there's a banana(s) and three apple(s).

Primeiro, dividimos a string em uma lista de palavras: ["there's", "a", "banana(s)", "and", "three", "apple(s)"]

Para o segundo passo, tomamos as duas palavras que terminam com (s): banana(s)e apple(s).

A palavra anterior banana(s)é a, então removemos o (s), tornando-o banana. A palavra anterior apple(s)é three, então alteramos o (s)para s, assim ele se torna apples.

Agora temos ["there's", "a", "banana", "and", "three", "apples"]. Juntando a lista novamente, chegamos there's a banana and three apples. Este é o nosso resultado final.

Os desafios)

Crie um programa ou função que use uma string ambígua em qualquer formato razoável e retorne a versão não ambígua dessa string.

Você pode assumir que a sequência não contém novas linhas, guias ou retornos de carro.

Eu esqueci de especificar se dividir em grupos de espaços ou espaços (ou seja, se okay thendois espaços devem ser ["okay", "then"]ou ["okay", "", "then"]) ao postar o desafio, então você pode assumir qualquer forma de divisão.

Casos de teste)

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

Pontuação

Como se trata de , a submissão com o mínimo de bytes vence!

LyricLy
fonte
Esta pergunta foi colocada na área restrita .
usar o seguinte código
O apple(s)caso de teste deve render em applesvez disso? O desafio indica Otherwise, if the word is the first word in the string . . . replace the (s) at the end of the word with s.que esse caso rendeu applesem sandbox para as três primeiras revisões, mas mudou na quarta.
Fireflame241 01/10/19
@ fireflame241 Ao escrever o segundo rascunho das regras, eu faria isso para que o início da string não fosse alterado. Mudei essa regra mais tarde, mas não o caso de teste. Boa pegada.
precisa saber é o seguinte
Sugestão de caso de teste: There's a single banana(s)-> There's a single bananas.
Jonathan Allan
1
@JonathanAllan Você não pode. Vou adicionar alguns casos de teste.
LyricLy

Respostas:

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

Explicação

j=" ";k=Except@j

Defina jpara um caractere de espaço em branco. Defina kcomo o padrão "não j" (= caractere que não é um espaço em branco).

j<>j<>#<>j

Anexe dois espaços em branco e anexe um (s) espaço em branco à entrada.

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

Para uma substring que corresponde ao padrão:

  1. Um espaço em branco, seguido por
  2. uma substring comprimento zero ou mais longo, consistindo apenas em caracteres que não são espaços em branco (quantificador) (chame isso a), seguidos por
  3. uma substring de comprimento um ou mais, consistindo apenas em caracteres de espaço em branco (chame isso s), seguida de
  4. uma substring de comprimento um ou mais, consistindo apenas em caracteres que não sejam espaços em branco (palavra) (chame isso w), seguidos por
  5. a sequência "(s)", seguida por
  6. um espaço em branco
Se [FreeQ [a, "a" | "an" | "1" | "one"], "s", ""]]

Se anão for uma das palavras singulares, avalie para "s", caso contrário "".

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

Substituir o padrão de correspondência com j, a, s, w, If[FreeQ[a,"a"|"an"|"1"|"one"],"s",""], e jse uniram.

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

Pegue da posição 3 para a posição -2 (indexado a 1; índices negativos contam desde o final). Isso ocorre porque adicionamos três espaços no início.

JungHwan Min
fonte
3
Por que não usar o builtin para remover o 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

Experimente online!

-4 bytes graças a i cri everytim (acho que isso é aceitável)

HyperNeutrino
fonte
@JonathanAllan Corrigido, obrigado.
HyperNeutrino 01/10
1
__import__não pode ser mais curto ... Sim, é 4 bytes mais curto como um regular import re.
totallyhuman
@icrieverytim huh você está certo (apenas 3 bytes embora) graças
HyperNeutrino
@icrieverytim ._. Ah legal. obrigado!
HyperNeutrino 01/10/19
4

Retina , 53 bytes

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

Experimente online!

fireflame241
fonte
1
Isso exclui o espaço depois banana(s)em there's a banana(s) and three apple(s)- tentar essa correção
Neil
Você pode mudar a|ana an?para -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
fonte
3

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

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

Faça a correspondência de cada (s)no final da palavra, substitua-o por !$1(1 ou 0) esses.

Baixo
fonte
2

Pitão - 53 bytes

Segue o algoritmo praticamente como ele é.

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

Experimente online aqui .

Maltysen
fonte
1
Falha em there are two banana(s) and one leprechaun(s)(dois espaços após o one). O espaço em branco original é preservado, mas leprechaun(s)ignora o oneantes.
LyricLy
1
@LyricLy você não declarou isso explicitamente no OP. Com dois espaços (usando (1) de seu "método (s)" na seção "dividir a string em espaços em uma lista de palavras") não é realmente uma palavra vazia entre oneeleprechaun(s)
Jonathan Allan
2

Geléia ,  52 51  49 bytes

A geléia não possui um átomo de regex (s)

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

Um programa completo que aceita uma sequência de caracteres (usando a formatação Python, se for multilinha ou contenha aspas) e imprime a saída.

Experimente online! ou veja a suíte de testes .

Quão?

Ṫ - 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
fonte
Estou curioso para saber por que você usou como um link separado. Isso impede a exclusão do elemento da lista original?
HyperNeutrino 01/10/19
Não, eu preciso pegar o rabo do par ... escrevendo um comentário de código, talvez você consiga ver um golfe depois de ver isso.
Jonathan Allan
Ah ok. Obrigado, vou tentar identificar o golfe assim que houver um comentário (ou antes disso)!
HyperNeutrino 01/10/19
Portanto, os links 1, 2 e 3 são todos finais, e o link 5 escolhe quais chamar e usa Ŀpara fazer isso, mas não vejo uma maneira curta de seguir dentro do link 4, mas pode haver. Poderia até haver uma maneira de obter a cauda do link 4 lá também!
Jonathan Allan
@HyperNeutrino Acho que a Ŀcoisa pode chamar o primeiro link, é por isso que é um link por si só.
Erik the Outgolfer
2

Java (OpenJDK 8) , 91 83 96 bytes

s->s.replaceAll("((^| )(an?|1|one) +\\S+)\\(s\\)(?= |$)","$1").replaceAll("\\(s\\)(?= |$)","s");

Experimente online!

Nevay
fonte
1

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

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

Experimente online!

Xcali
fonte
1
Não nos casos de teste, mas acho que isso falha a hel(s)lo.
Neil
Está funcionando corretamente, conforme fornecido no caso de teste. É perto da parte inferior dos casos de teste no meu link TIO.
Xcali 01/10
Bem, eu vou ter que ficar a hel(s)loadicionados aos casos de teste, e então talvez você vai corrigir o seu 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'))

Explicação em breve.

XavCo7
fonte
1
você pode substituir \spor `` de acordo com "Você pode assumir que a string não contém novas linhas, guias ou retornos de carro".
SuperStormer
Falha em "este é um te (s) t". Você pode corrigir adicionando (\s|$)ao final da regex.
precisa saber é o seguinte
Também falha em "maçã (s)". Corrigido neste TIO
Birjolaxew 2/17/17
Graças @Birjolaxew, editar vontade nas mudanças quando eu posso ...
XavCo7
0

JavaScript (ES6), 84 bytes

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

Aqui está uma maneira interessante de reorganizar a última parte, que infelizmente é 2 bytes mais longa:

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

JavaScript (SpiderMonkey) , 82 bytes

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

Experimente online!

Versão de 78 bytes (menos robusta)

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

Esta é uma versão modificada do ETHproductions '(não tenho 50 representantes).

Explicação

  • /(\S+ +(\S+))\(s\)/g- o padrão real a ser procurado ( amount object(s))
  • (_,a)=>a- _é uma variável catch toda, aé o(\S+ +(\S+))
  • "s"[+/^(1|one|an?)/i.test(a)]||""- em vez de cortar a matriz, basta criar uma matriz fictícia e obter o índice ( +/.../.testretorna um número)
    • deve "s"[+/^(1|one|an?)/i.test(a)]retornar undefined( true, ou 1para o teste) retornar""
Ephellon Dantzler
fonte