[Question]
  [
Programming is very rigid. You can't tell a program to "output the banana count", you have to tell it to `print(bananas)`.
But when you do that, you end up with a problem: you don't know how many bananas you have beforehand, so you don't know whether to use a plural.
Sometimes, programmers go the lazy way. Instead of checking, they just print `there are X banana(s)`.
But that's ugly, so we need a program to fix this.
# The method(s)
To remove the ambiguous plurals in a string, follow the following steps:
1. Split the string on spaces into a list of words.
2. For every word that ends with `(s)`, do the following:
	* If the preceding word is `a`, `an`, `1` or `one`, remove the `(s)` at the end of the word.
	* Otherwise, if the word is the first word in the string or the preceding word is not `a`, `an`, `1` or `one`, replace the `(s)` at the end of the word with `s`.
3. Join the list of words back together into a string, preserving the original whitespace.
### Example(s)
Let's take a string `there's a banana(s) and three apple(s)`.
First, we split the string into a list of words: `["there's", "a", "banana(s)", "and", "three", "apple(s)"]`
For the second step, we take the two words ending with `(s)`: `banana(s)` and `apple(s)`.
The word before `banana(s)` is `a`, so we remove the `(s)`, making it `banana`. 
The word before `apple(s)` is `three`, so we change the `(s)` to `s`, thus it becomes `apples`.
We now have `["there's", "a", "banana", "and", "three", "apples"]`. Joining the list back together, we get `there's a banana and three apples`. This is our end result.
# The challenge(s)
Create a program or function that takes an ambiguous string in [any reasonable format](https://codegolf.meta.stackexchange.com/questions/2447/default-for-code-golf-input-output-methods) and returns the un-ambiguated version of that string.
You may assume the string contains no newlines, tabs or carriage returns.
I forgot to specify whether to split on groups of spaces or spaces (i.e. whether `okay then` with two spaces should be `["okay", "then"]` or `["okay", "", "then"]`) when posting the challenge, so you may assume either form of splitting.
# Test case(s)
```
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
```
# Scoring
As this is [code-golf](/questions/tagged/code-golf "show questions tagged 'code-golf'"), the submission with the least bytes wins!
  
[Answer]
# 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}&
```
### Explanation
```
j=" ";k=Except@j
```
Set `j` to a whitespace character(s). Set `k` to the pattern "not `j`" (= non-whitespace character).
```
j<>j<>#<>j
```
Prepend two whitespace(s) and append one whitespace(s) to the input.
```
j~~a:k...~~s:j..~~w:k..~~"(s)"~~j
```
For a substring(s) matching the pattern:
1. One whitespace(s), followed by
2. a length-zero or longer substring consisting of only non-whitespace character(s) (quantifier) (call this `a`), followed by
3. a length-one or longer substring consisting of only whitespace character(s) (call this `s`), followed by
4. a length-one or longer substring consisting of only non-whitespace character(s) (word) (call this `w`), followed by
5. the string `"(s)"`, followed by
6. a whitespace(s)
```
If[FreeQ[a,"a"|"an"|"1"|"one"],"s",""]
```
If `a` is not one of the singular word(s), evaluate to `"s"`, otherwise `""`.
```
StringReplace[..., ... :>{j,a,s,w,If[FreeQ[a,"a"|"an"|"1"|"one"],"s",""]}<>j]
```
Replace the matching pattern with `j`, `a`, `s`, `w`, `If[FreeQ[a,"a"|"an"|"1"|"one"],"s",""]`, and `j` joined together.
```
... ~StringTake~{3,-2}
```
Take from position 3 to position -2 (1-indexed; negative indices count from the end). This is because we added three space(s) in the beginning.
[Answer]
# [Python 3](https://docs.python.org/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
```
[Try it online!](https://tio.run/##lZPRasIwFIavzVMcwmAJ1kLnnaC73jMsY6Sa2kBMw0mcDHz37lRbJ06kS@lFT//vT86fJHynuvHz1u5CgwnQsGqpWqd35UZDzHCJJo/7coECuRJRSQHHJ8kzHnl2qpVC@9djcWy8kULFqRT5VJ6UJOCqUC9qzrMoJbtM0SYT0@daRxNhCZxzlmqDBjS96dBAqT09IkrQfgNkDM4ENOta731Xna3gHhDvyM/Oz/TrxjXVaMggBGe6Uj8G5yvgVh3ZLfR4kGXPdSsbzxJ3AVhxtfpR6ACwvgkYvdieowCjwS/TVRu0W@u1O2sOtaX9C3p91QdxY4DIin910jUyAJS7/0d8p9x7gNXGEeSa0SEMAHsDvaOjQB8Jtd8afDg5kX8ARuf7vVjMig/GqgbBWdpV6@H3DuQxOJsEV57LBZs4U6UMKME60e3o5INgtuKSTQJan0QlOl0eE9ogpJTtDw "Python 3 – Try It Online")
-4 bytes thanks to i cri everytim (I think this is acceptable)
[Answer]
# [Retina](https://github.com/m-ender/retina), 53 bytes
```
(( |^)(a|an|1|one) [^ ]*)\(s\)( |$)
$1
\(s\)( |$)
s$1
```
[Try it online!](https://tio.run/##K0otycxL/P9fQ0OhJk5TI7EmMa/GsCY/L1VTITpOIVZLM0ajOEYTKKmiyaViyIXEK1Yx/P/fUyExVyFRobikKDEvPbWo@D8A "Retina – Try It Online")
[Answer]
# 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)&
```
[Answer]
## Perl 5, 43 + 1 (-p) = 44 bytes
```
s/\b((one|1|an?) +)?\S+\K\(s\)\B/"s"x!$1/ge
```
Match every `(s)` at end of word, replace it with `!$1` (1 or 0) esses.
[Answer]
# Pyth - 53 bytes
Follows the algorithm pretty much as it is.
```
K+kczdjdt.e?q"(s)"gb_2+<b_3*\s!}@Ktk[\a"an""one"\1)bK
```
[Try it online here](http://pyth.herokuapp.com/?code=K%2Bkczdjdt.e%3Fq%22%28s%29%22gb_2%2B%3Cb_3%2a%5Cs%21%7D%40Ktk%5B%5Ca%22an%22%22one%22%5C1%29bK&input=there+are+two+banana%28s%29+and+one+leprechaun%28s%29&debug=0).
[Answer]
# [Jelly](https://github.com/DennisMitchell/jelly), ~~52 51~~ 49 [bytes](https://github.com/DennisMitchell/jelly/wiki/Code-page)
Jelly has not got one regex(s) atom
```
Ṫ
Ñ;”s
Ṫḣ-3
UṪw“)s(”⁼1
“µḣ⁴µuʠg*»ḲċḢ‘×Ç‘
⁶;ḲÇĿ2ƤK
```
A full program accepting a string (using Python formatting if multiline or containing quotes) and printing the output.
**[Try it online!](https://tio.run/##y0rNyan8///hzlVchydaP2qYW8wFZD/csVjXmCsUyCp/1DBHs1gDKPGocY8hF5B3aCtQ9lHjlkNbS08tSNc6tPvhjk1Huh/uWPSoYcbh6YfbgRTXo8Zt1kDhw@1H9hsdW@L9//9/38Ti5PwSjWJNhcSiVAUjhaTEPCAE8/NSFAwVclILilKTMxJL80BiCnp6egoKSaUlCvl5qQqZxQq5mcVA8cy8dIVEheLEUhAnMT0VpLQoPydHB2xIYp5CYkFRPtiAkvx8RQA "Jelly – Try It Online")** or see the [test-suite](https://tio.run/##XU69SgNBEO73KaYzESyiZZ5ArC0sxzjcnqx7x@7FI92dTQorKy0URK3EShI5iSDchRS@xe6LrJMLScQZlvlmvh/2nJQaheA@X0Vz0/fFgxWMXfW8dyCOGeW@uO/aDhO@/OoJ3uops76c1NPhz2O0W89c9T6/dtWTL@6a22bMQ/jyo8/nZjz/3l@8HAU3mzBx9XYSQibJECC/LE/gFDV3x3YB9RkkmkBRamggcaj5Klr1jgX8p8ykIU5JU0VL2QYsEzZLb2sSKyQ425K5JOBKTBzFGhW0lcs4I5viYGX960W9zZSkeKhEHAJe8Ld4yQzqiEyrhDX/Cw "Jelly – Try It Online").
### How?
```
Ṫ - 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
```
[Answer]
# [Java (OpenJDK 8)](http://openjdk.java.net/), ~~91~~ ~~83~~ 96 bytes
```
s->s.replaceAll("((^| )(an?|1|one) +\\S+)\\(s\\)(?= |$)","$1").replaceAll("\\(s\\)(?= |$)","s");
```
[Try it online!](https://tio.run/##nZLBTgIxEIbvPMVkQ2IbZBPOKMSjB/FAPLmaDMvAFkvbtLPgRnh27AKJQT3sMr01/zf9pu0KN9i3jsxq/nFw5UyrHHKNIcATKgNfHYgVGDnuL5RBDatIpCUrnS5Kk7OyJn0x6KtnRx7Z@rspe2WWI5jA/SH0RyH15DTm9KC1SIR434EUaMa7wc4aktDLsmlPZpkIWSbF@B52XZncJt1BIi/IP4mQyOGh1ht2jpZn@7Psxqo5rOMM4uTz@gbol0GeR6prWgWmdWpLTl2MsDZikqJzuhIJF@QpEgS8tTBDE5eINJo5RG3Q5DzlBZYm7iZSDpt3vQmAvzpy4SmeFkPUpl1roDZvDQ1@ZBszJ6JxPN5lIL@hOme9Wh4/2rG2hWIKLn6CVsrXOKNpfzdcqACqflCuOW4MPgKuI1UzHs2SfMtTPVf9q17zH7Y/s58XPfad/eEb "Java (OpenJDK 8) – Try It Online")
[Answer]
# [Perl 5](https://www.perl.org/), 56 + 1 (`-p`) = 57 bytes
```
s/\b(an?|1|one) +\S+\K\(s\)(?= |$)//g;s/\(s\)( |$)/s$1/g
```
[Try it online!](https://tio.run/##XY5PC8IwDMXv@xQ5CG6Ibjt4EvEs4slrL1HDOqhpaate9tmtWcU/mFKal7z3o468WaYUanUskTdDO1imCmbqMFM7VQZVlZs1DJOqrruVuPIk6zBp6y6lqMkToNx4t3BEllOGCpDPICgw5DydNF5ZpkV2TwPgnzNqT0JxztBo@zQj4SPab6h4dYWwA/kbgZT1fdczGsh1132k4PD0iv5mkb9MTUYeY4st4EW@JSJ65I58dsJ7/7Au9pZDmu@Xi6Zt0tw9AQ "Perl 5 – Try It Online")
[Answer]
## 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'))
```
Explanation coming soon.
[Answer]
## JavaScript (ES6), 84 bytes
```
s=>s.replace(/((^|\S+ +)\S+)\(s\)(?!\S)/g,(_,a)=>a+(/^(1|an?|one) /.test(a)?'':'s'))
```
Here's an interesting way to rearrange the last part, which is sadly 2 bytes longer:
```
s=>s.replace(/((^|\S+ +)\S+)\(s\)(?!\S)/g,(_,a)=>a+'s'.slice(/^(1|an?|one) /.test(a)))
```
[Answer]
# [JavaScript (SpiderMonkey)](https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/Releases/45), 82 bytes
```
s=s.replace(/(\S+ +(\S+))\(s\)\B/g,(_,a)=>a+("s"[+/^(1|one|an?)\b/i.test(a)]||""))
```
[Try it online!](https://tio.run/##XVHBbsMgDL3nKywuA6VL1nOWTdpt5x2bbnITL2GjgIC0mpR/zyCNtK5GgP14fgbzhSf0rZM23HsrO3JHo7/pZy5LwK6jDpgjq7ClmntRPzH4NA5GT3AgZc7ApY6ICeREdkIHVo0O1YU7@9oXazYvefOWQ55WIRruG9G8lP2Gf2wwUjHnzLNdXr7z7WQ0TaifRXMoZRHIB45iP02MCTFXqYjUdgxQZ6zJwkCOAOMMZwMH1HHE4oC6g6gDiqyjdsBRR7TRa8KdB7whh8FRFLJW0cq89pPUdbz9y07hJUherObJnQiiGSd7qVHBYudBxrfY1ItV40YE9b8SYZAeZLpoSFBI2CvgMQIpdKh7ciuXFd4qGThrNBNVlsU/4kujoIaHDai4LT0rFOk@DFU8eAQVtzwXGUBrtDeKCmV6fvlAvtB3ci9ENf8C "JavaScript (SpiderMonkey) – Try It Online")
### 78 Byte version (less robust)
```
s=s.replace(/(\S+ +(\S*))\(s\)/g,(_,a)=>a+("s"[+/^(1|one|an?)/i.test(a)]||""))
```
This is a modified version of ETHproductions' (I don't have 50 rep.)
### Explanation
* `/(\S+ +(\S+))\(s\)/g` - the actual pattern to look for (`amount object(s)`)
* `(_,a)=>a` - `_` is a catch all variable, `a` is the `(\S+ +(\S+))`
* `"s"[+/^(1|one|an?)/i.test(a)]||""` - instead of slicing the array, just make a dummy array and get the index (`+/.../.test` returns a number)
	+ should `"s"[+/^(1|one|an?)/i.test(a)]` return `undefined` (`true`, or `1` for the test) return `""`
]