An A , or An An?

21

3

In English, there is the fun and simple difference between an and a: you use an when preceding a word starting with a vowel sound, and a when the word starts with a consonant sound.

For the sake of simplicity in this challenge, an precedes a word that starts with a vowel (aeiou), and a precedes a word that starts with a consonant.

Input

A string comprising only printable ASCII characters, with [?] appearing in places where you must choose to insert an or a. [?] will always appear before a word. You can assume that the sentence will be grammatically correct and formatted like normal.

Output

The input string with [?] replaced with the appropriate word (an or a). You do have to worry about capitalization!

When to Capitalize

Capitalize a word if it is preceded by no characters (is the first one in the input) or if it is preceded by one of .?! followed by a space.

Examples

Input: Hello, this is [?] world!
Output: Hello, this is a world!

Input: How about we build [?] big building. It will have [?] orange banana hanging out of [?] window.
Output: How about we build a big building. It will have an orange banana hanging out of a window.

Input: [?] giant en le sky.
Output: A giant en le sky.

Input: [?] yarn ball? [?] big one!
Output: A yarn ball? A big one!

Input: [?] hour ago I met [?] European.
Output: A hour ago I met an European.

Input: Hey sir [Richard], how 'bout [?] cat?
Output: Hey sir [Richard], how 'bout a cat?

This is , so shortest code in bytes wins!

Daniel

Posted 2016-09-15T03:10:31.813

Reputation: 6 425

OK thanks. Can we assume no inputs will have extra spaces between the [?] and the word? – James – 2016-09-15T03:20:37.777

@DJMcMayhem, you can assume that the sentences will be grammatically correct – Daniel – 2016-09-15T03:21:30.910

@Dopapp I pronounce historian as historian, but I was taught to say it as an historian. (Pronounced as an istorian) It is hotly debated though: http://www.google.com/search?q=%22an+historian"

– DanTheMan – 2016-09-15T03:25:02.970

8Does a/an have to be capitalized in the middle of the input when it comes at the beginning of a sentence? ("This is [?] test. [?] test.") If so, what punctuation can a sentence end with? What about sentences in quotation marks or parentheses? Or abbreviations that end in a period ("E.g. [?] input like this")? Capitalization rules have lots of weird special cases, so please be very explicit about what our programs do or don't need to handle. – DLosc – 2016-09-15T04:25:47.363

1Could you please clarify when to capitalize? The first character? – James – 2016-09-15T04:50:49.053

34You should add the test case [?] hour ago I met [?] European. just to make everyone cringe. – Martin Ender – 2016-09-15T09:03:00.820

@DLosc, I have made an edit to specify when to capitalize. Is it clear now? – Daniel – 2016-09-15T11:08:41.450

>

  • What about [?]other example? 2, I guess we can expect that [?] is not at the end of the text or a sentence.
  • < – Titus – 2016-09-15T11:12:28.337

    @Titus 1. There won't be anything like that. 2. Correct – Daniel – 2016-09-15T11:17:36.910

    @DJMcMayhem, I edited it. Is it clearer when to capitalize? – Daniel – 2016-09-15T11:20:08.653

    @MartinEnder You are so evil... that is soooo wrong... – beaker – 2016-09-15T15:32:30.093

    1Now we must have [?] hour ago I met [?] horse. – beaker – 2016-09-15T15:39:37.450

    @Dopapp Yes, that's much clearer. Now it just needs a couple test cases with sentence-initial [?] after multiple different punctuation characters. – DLosc – 2016-09-15T22:05:44.637

    @DLosc see the last test case – Daniel – 2016-09-15T23:19:48.670

    What about “An honest” or “A unicorn”? English is great. – Stan Strum – 2017-12-06T18:28:33.120

    Answers

    6

    V, 41 bytes

    ÍãÛ?Ý ¨[aeiou]©/an
    ÍÛ?Ý/a
    Í^aü[.!?] a/A
    

    Try it online!, which conveniently can also be used to verify all test cases with no extra byte count.

    This takes advantage of V's "Regex Compression". It uses a lot of unprintable characters, so here is a hexdump:

    0000000: cde3 db3f dd85 20a8 5b61 6569 6f75 5da9  ...?.. .[aeiou].
    0000010: 2f61 6e0a cddb 3fdd 2f61 0acd 5e61 fc5b  /an...?./a..^a.[
    0000020: 2e21 3f5d 2093 612f 41                   .!?] .a/A
    

    James

    Posted 2016-09-15T03:10:31.813

    Reputation: 54 537

    Unfortunately, OP said "You do have to worry about capitalization!" (emphasis mine). – El'endia Starman – 2016-09-15T04:43:48.633

    1@El'endiaStarman Oh I misread that. I can fix it, but I have no clue what to capitalize, since OP didn't specify. – James – 2016-09-15T04:54:46.007

    @El'endiaStarman Fixed now. – James – 2016-09-15T16:22:24.957

    7

    Perl, 48 bytes

    Saved 1 byte due to Ton Hospel.

    #!perl -p
    s;\[\?];A.n x$'=~/^ [aeiou]/i^$"x/[^.?!] \G/;eg
    

    Counting the shebang as one, input is taken from stdin.

    Explanation

    #!perl -p               # for each line of input, set $_, auto-print result
    
    s;                      # begin regex substitution, with delimiter ;
    \[\?]                   # match [?] literally, and replace with:
    ;
    A.n x$'=~/^ [aeiou]/i   # 'A', concatenate with 'n' if post-match ($')
                            #   matches space followed by a vowel
    ^$"x/[^.?!] \G/         # if the match is preceded by /[^.?!] /, xor with a space
                            #   this will change An -> an
    
    ;eg                     # regex options eval, global
    

    Sample Usage

    $ echo Hello, this is [?] world! | perl a-an.pl
    Hello, this is a world!
    
    $ echo How about we build [?] big building. It will have [?] orange banana hanging out of [?] window. | perl a-an.pl
    How about we build a big building. It will have an orange banana hanging out of a window.
    
    $ echo [?] giant en le sky. [?] yarn ball? | perl a-an.pl
    A giant en le sky. A yarn ball?
    
    $ echo [?] hour ago I met [?] European. | perl a-an.pl
    A hour ago I met an European.
    

    primo

    Posted 2016-09-15T03:10:31.813

    Reputation: 30 891

    2Could you explain this, please? – sudee – 2016-09-15T07:30:51.723

    1Support for capitalization after /[.?!]/ followed by space is missing – Ton Hospel – 2016-09-15T13:33:47.143

    1@TonHospel 10 hours ago, the problem made no mention of this. – primo – 2016-09-15T15:30:54.027

    2Ok, changing the spec on the fly is so unfair. PS: I love using \G to go backwarsds. PPS, a bit shorter: s;\[\?];A.n x$'=~/^ [aeiou]/^$"x/[^.?!] \G/;eg – Ton Hospel – 2016-09-15T15:50:30.230

    1@sudee updated to include explanation. – primo – 2016-09-16T01:23:32.987

    7

    Ruby, 78 72 bytes

    ->s{s.gsub(/(^|\. )?\K\[\?\]( [aeiou])?/i){"anAn"[$1?2:0,$2?2:1]+"#$2"}}
    

    Ungolfed

    def f(s)
        s.gsub(/(^|\. )?\[\?\]( [aeiou])?/i) do |m|
            capitalize = $1
            vowel = $2
            replacement = if vowel then
                capitalize ? "An" : "an"
            else
                capitalize ? "A" : "a"
            end
            m.sub('[?]', replacement)
        end
    end
    

    sudee

    Posted 2016-09-15T03:10:31.813

    Reputation: 551

    2"anAn"[...] is really clever. You can save a few bytes by skipping the inner sub: s.gsub(/(^|\. )?\K\[\?\] ([aeiou])?/i){"anAn"[$1?2:0,$2?2:1]+" #$2"} – Jordan – 2016-09-15T13:43:32.197

    6

    PHP, 207 bytes

    foreach(explode("[?]",$s)as$i=>$b){$r=Aa[$k=0|!strstr(".!?",''==($c=trim($a))?".":$c[strlen($c)-1])].n[!preg_match("#^['\"´`\s]*([aeiou]|$)#i",$d=trim($b))];echo$i?$r.$b:$b;$a=$i?''==$d?a:$b:(''==$d?".":a);}
    

    I like solutions more complete from time to time ...
    but I must admit that this is a little overkill, although it´s not at all finished.

    Save to file, run with php <filename> with input from STDIN.

    test cases

    How about we build [?] big building ... with [?] orange banana hanging out of [?] window.
    =>  How about we build a big building ... with an orange banana hanging out of a window.
    
    Hello, this is [?] world!               =>  Hello, this is a world!
    Should I use [?] '[?]' or [?] '[?]'?    =>  Should I use an 'an' or an 'a'?
    [?] elephant in [?] swimsuit.           =>  An elephant in a swimsuit.
    
    How I met your moth[?].                 =>  How I met your motha.
    b[?][?][?] short[?]ge!                  =>  banana shortage!
    

    breakdown

    foreach(explode("[?]",$s)as$i=>$b)
    {
        $r=
            // lookbehind: uppercase if the end of a sentence precedes
            Aa[$k=0|!strstr(".!?",''==($c=trim($a))?".":$c[strlen($c)-1])]
            .
            // lookahead: append "n" if a vowel follows (consider quote characters blank)
            n[!preg_match("#^['\"´`\s]*([aeiou]|$)#i",$d=trim($b))]
        ;
        // output replacement and this part
        echo$i?$r.$b:$b;
        // prepare previous part for next iteration
        $a=$i               // this part was NOT the first:
            ?   ''==$d
                ? a             // if empty -> a word ($r from the previous iteration)
                : $b            // default: $b
            :  (''==$d      // this WAS the first part:
                ? "."           // if empty: end of a sentence (= uppercase next $r)
                : a             // else not
            )
        ;
        // golfed down to `$a=!$i^''==$d?a:($i?$b:".");`
    }
    

    Titus

    Posted 2016-09-15T03:10:31.813

    Reputation: 13 814

    3Upvote for "banana shortage"! LOL – MonkeyZeus – 2016-09-15T14:57:48.460

    @MonkeyZeus: Try [?][?][?]s [?]lert! – Titus – 2016-09-15T16:58:07.610

    All I can imagine is a heartbroken Donkey Kong worried sick about the shortage now :( – MonkeyZeus – 2016-09-15T18:09:37.300

    5

    Minkolang 0.15, 75 bytes

    od4&r$O."]?["30$Z3&00w4X"Aa"I2-"Aa ."40$Z,*2&$rxr$O" aeiou"od0Z1=3&"n"r5X$r
    

    Try it here!

    Explanation

    od                                                                    Take character from input and duplicate (0 if input is empty)
      4&                                                                  Pop top of stack; jump 4 spaces if not 0
        r$O.                                                              Reverse stack, output whole stack as characters, and stop.
    
        "]?["                                                             Push "[?]" on the stack
             30$Z                                                         Pop the top 3 items and count its occurrences in the stack
                  3&                                                      Pop top of stack; jump 3 spaces if not 0
                    00w                                                   Wormhole to (0,0) in the code box
    
                    3X                                                    Dump the top 3 items of stack
                      "Aa"                                                Push "aA"
                          I2-                                             Push the length of stack minus 2
                             "Aa ."40$Z,                                  Push ". aA" and count its occurrences, negating the result
                                        *                                 Multiply the top two items of the stack
                                         2&$r                             Pop top of stack and swap the top two items if 0
                                             x                            Dump top of stack
                                              r                           Reverse stack
                                               $O                         Output whole stack as characters
                                                 " aeiou"                 Push a space and the vowels
                                                         od               Take a character from input and duplicate
                                                           0Z             Pop top of stack and count its occurrences in the stack (either 1 or 2)
                                                             1=           1 if equal to 1, 0 otherwise
                                                               3&         Pop top of stack; jump 3 spaces if not 0
                                                                 "n"      Push "n" if top of stack is 0
    
                                                                 r        Reverse stack
                                                                  5X      Dump top five items of stack
                                                                    $r    Swap top two items of stack
    

    Note that because Minkolang is toroidal, when the program counter moves off the right edge, it reappears on the left. Certainly golfable, but because I had to add 21 bytes because of the spec, I may not try.

    El'endia Starman

    Posted 2016-09-15T03:10:31.813

    Reputation: 14 504

    6Am I the only one who wants to go play excitebike after reading that explanation? – Magic Octopus Urn – 2016-09-15T12:17:10.557

    3

    JavaScript (ES6), 90 86 87 85

    Edit once more as the spec for capitalization has changed (more sensible now)

    Edit again 1 byte save thx @Huntro

    Edit 2 more bytes to manage quotes and the like, as pointed out by IsmaelMiguel (even if I don't know if it's requested by op). Note that previously I had counted 86 bytes but they were 85

    Trying to follow the capitalization rule stated in the comments event if it's incomplete (at least)

    x=>x.replace(/([^!?.] )?\[\?](\W*.)/g,(a,b,c)=>(b?b+'a':'A')+(/[aeiou]/i.test(c)?'n'+c:c))
    

    Test

    f=x=>x.replace(/([^!?.] )?\[\?](\W*.)/g,(a,b,c)=>(b?b+'a':'A')+(/[aeiou]/i.test(c)?'n'+c:c))
    
    function go() {
      var i=I.value, o=f(i)
      O.innerHTML = '<i>'+i+'</i>\n<b>'+o+'</b>\n\n'+O.innerHTML 
    }
    
    go()
    #I { width:80% }
    <input value='How about we build [?] big building. It will have [?] orange banana hanging out of [?] window.' id=I><button onclick='go()'>GO</button><pre id=O></pre>

    edc65

    Posted 2016-09-15T03:10:31.813

    Reputation: 31 086

    Shouldn't [?][?] give Ana? And shouldn't [?][?] a. produce Ana a.? – Ismael Miguel – 2016-09-15T09:05:13.523

    @IsmaelMiguel I don't understand exactly what you mean, but anyway [?] will always appear before a word. You can assume that the sentence will be grammatically correct and formatted like normal. – edc65 – 2016-09-15T09:07:03.593

    Got it, but your code is giving weird results for [?] "[?]". (An "A", the quotes are irrelevant) and for [?] "A". (it works fine for [?] A.). – Ismael Miguel – 2016-09-15T09:29:14.103

    @IsmaelMiguel [?] "[?]" is not valid input. [?] will always appear before a word and "[?]" is not a word. – edc65 – 2016-09-15T09:37:58.977

    You're right, but on the 2nd example, "A" is a word in itself, right? If so, then the output of [?] "A". is incorrect. – Ismael Miguel – 2016-09-15T09:41:09.070

    @IsmaelMiguel got your point – edc65 – 2016-09-15T09:52:55.493

    It is almost working perfectly. Testing with [?] "A". [?] 'A'. [?]. [?] A. gives An "A". An 'A'. An. [?] A., when it should be An "A". An 'A'. A. An A.. The [?]. isn't important, but the [?] A. is now broken. Notice that [?] A. on itself works fine! It just breaks on that sentence. – Ismael Miguel – 2016-09-15T09:58:23.390

    2The escaping of second ] is not need. /(\w )?\[\?](\W*.)/g – Huntro – 2016-09-15T10:37:08.157

    @IsmaelMiguel: [?] will never occur at the end of a sentence. – Titus – 2016-09-15T12:08:26.563

    Sentences usually end with [?] dot, [?] exclamation mark or [?] question mark. – Titus – 2016-09-15T12:10:56.023

    @Titus On the input [?] "A". [?] 'A'. [?]. [?] A., the result of [?]. [?] A. is incorrect. It should be A. An A. and it returns An. [?] A.. BUT I'm only interested in the [?] A., which is wrong in that example, but works fine on it's own. – Ismael Miguel – 2016-09-15T14:09:22.440

    @IsmaelMiguel that input is invalid as [?] will always appear before a word. (maybe I already told you) and . is not a word – edc65 – 2016-09-15T14:09:34.380

    2

    05AB1E, 38 36 35 bytes

    2FžNžM‚NèSðì…[?]©ìDu«D®'a'nN׫::}.ª
    

    Try it online or verify all test cases.

    Explanation:

    2F            # Loop 2 times:
      žN          #  Push consonants "bcdfghjklmnpqrstvwxyz"
      žM          #  Push vowels "aeiou"
        ‚         #  Pair them together into a list
         Nè       #  And use the loop-index to index into this pair
      S           #  Convert this string to a list of characters
       ðì         #  Prepend a space in front of each character
         …[?]     #  Push string "[?]
             ©    #  Store it in variable `®` (without popping)
              ì   #  And prepend it in front of each string in the list as well
      }D          #  Then duplicate the list
        u         #  Uppercase the characters in the copy
         «        #  And merge the two lists together
                  #   i.e. for the vowel-iteration we'd have ["[?] a","[?] e","[?] i","[?] o",
                  #    "[?] u","[?] A","[?] E","[?] I","[?] O","[?] U"]
       D          #  Duplicate it
        ®         #  Push "[?]" from variable `®`
         'a      '#  Push "a"
           'n    '#  Push "n"
             N×   #  Repeated the 0-based index amount of times (so either "" or "n")
               «  #  And append it to the "a"
        :         #  Replace all "[?]" with "an"/"a" in the duplicated list
         :        #  And then replace all values of the lists in the (implicit) input-string
     }.ª          #  After the loop: sentence-capitalize everything (which fortunately retains
                  #  capitalized words in the middle of sentences, like the "European" testcase)
                  # (and after the loop the result is output implicitly)
    

    Kevin Cruijssen

    Posted 2016-09-15T03:10:31.813

    Reputation: 67 575

    1There's a little bug in it. It capitalizes each word after an "an". For example "[?] orange" becomes "an Orange". Seems to work, if you add a ] after the :: – Dorian – 2019-10-01T15:25:56.833

    @Dorian Woops.. I removed that } later on because I thought it would save a byte, but you're indeed right that it fails for [?] vowel cases.. Thanks for letting me know! – Kevin Cruijssen – 2019-10-01T15:29:21.480

    2

    Batch, 136 bytes

    @set/ps=
    @for %%v in (a e i o u)do @call set s=%%s:[?] %%v=an %%v%%
    @set s=%s:[?]=a%
    @if %s:~0,1%==a set s=A%s:~1%
    @echo %s:. a=. A%
    

    Takes a line of input on STDIN.

    Neil

    Posted 2016-09-15T03:10:31.813

    Reputation: 95 035

    2

    Python 3.5.1, 153 147 141 124 Bytes

    *s,=input().replace('[?]','*');print(*['aA'[i<1or s[i-2]in'.?!']+'n'*(s[i+2]in 'aeiouAEIOU')if c=='*' else c for i,c in enumerate(s)],sep='')
    

    Input :

    [?] apple [?] day keeps the doctor away. [?] lie.

    Output :

    An apple a day keeps the doctor away. A lie.

    123 Bytes version - This does not handle capitalization rule.

    s=list(input().replace('[?]','*'));print(*['a'+'n'*(s[i+2]in 'aeiouAEIOU')if c=='*'else c for i,c in enumerate(s)],sep='')
    

    Try it online!

    Gurupad Mamadapur

    Posted 2016-09-15T03:10:31.813

    Reputation: 1 791

    1Welcome to Codegolf. You could use ; and golf it. – ABcDexter – 2016-09-15T11:09:27.463

    Thank you.I do not know how to golf. Let me find out. – Gurupad Mamadapur – 2016-09-15T11:13:54.103

    1m.start() for should be m.start()for, s[i+2] in 'aeiouAEIOU' should be s[i+2]in'aeiouAEIOU'. An easy -3-byte shave due to whitespace. – Erik the Outgolfer – 2016-09-15T11:42:34.093

    1('an','a')[s[i+2]in'aeiouAEIOU'] is inverted, you could use 'a'+'n'*(s[i+2]in'aeiouAEIOU') to fix that and save 2 bytes. Here you can find a lot of tips to golf. – Rod – 2016-09-15T11:54:30.160

    you can replace the for with a list comprehension : ['a'+'n'*(s[i+2]in'aeiouAEIOU')if s[i]=='*'else s[i]for i in range(len(s))] 3 bytes longer, but then you can drop the list() conversion, and use inside the print print(*['a'+'n'*(s[i+2]in'aeiouAEIOU')if s[i]=='*'else s[i]for i in range(len(s))],sep='') saving 4 bytes overall c: – Rod – 2016-09-15T14:23:46.397

    You can save several bytes by using enumerate as well: print(*['a'+'n'*(s[i+2]in 'aeiouAEIOU')if c=='*'else c for i,c in enumerate(s)],sep=''). – chepner – 2016-09-15T14:28:58.807

    1This community is so lovely, seeing how many people are willing to help a newcomer and provide golfing tips! – yo' – 2016-09-15T15:41:40.987

    1Wow enumerate() is cool. Thanks @chepner. – Gurupad Mamadapur – 2016-09-15T16:17:36.267

    Unless i can be negative (which I don't think it can), i==0 or can become i<1or – Cyoce – 2016-09-16T16:58:23.630

    @Cyoce Thanks. Totally missed that one. – Gurupad Mamadapur – 2016-09-16T17:12:32.600

    1Good job, even without regex! You can use 'aA' instead of ['a','A'], also try replacing T if C else F with C and T or F to save a few bytes. – Matthew Jensen – 2019-10-01T00:21:40.757

    @MatthewJensen Thanks! for aA trick. But wasn't able to work with the boolean one. – Gurupad Mamadapur – 2020-01-05T17:32:08.277

    2

    PHP, 100 92 bytes

    <?=preg_filter(["/\[\?]\K(?= [aeiou])/i","/([.?!] |^)\K\[\?]/","/\[\?]/"],[n,A,a],$argv[1]);
    

    It was possible to further golf the regular expressions.

    Gives a notice about an undefined constant but still works.

    Edit: 8 bytes saved thanks to primo

    user59178

    Posted 2016-09-15T03:10:31.813

    Reputation: 1 007

    It should also be possible to get your replacement array down to [n,A,a] by using look-around assertions (\K and (?= )). – primo – 2016-09-15T16:38:11.337

    2

    Java, 180178 bytes

    My first post here, I did use a part of the Kevin Cruijssen post but and up with a different approach, he helped me to reduce a bit more so, thanks to him !

    String c(String s){String x[]=s.split("\\[\\?]",2),r=x[0];return x.length>1?r+(r.matches("(.+[.!?] )|(^)$")?"A":"a")+("aeiouAEIOU".contains(""+x[1].charAt(1))?"n":"")+c(x[1]):r;}
    

    Here it is ungolfed :

    static String c(String s) {
            String x[] = s.split("\\[\\?\\]", 2), r = x[0];
            return x.length > 1 ? r + (r.matches("(.+[.!?] )|(^)$") ? "A" : "a")
                    + ("aeiouAEIOU".contains("" + x[1].charAt(1)) ? "n" : "") + c(x[1]) : r;
        }
    

    And the result

    A simple explanation, I use a recursive approch to find every [?].

    I couldn't find a way to use the matches with insensitive case (not sure it is possible).

    178bytes : Thanks to Martin Ender !

    AxelH

    Posted 2016-09-15T03:10:31.813

    Reputation: 151

    1Welcome to PPCG! I don't think you need to escape the ] in your regex. – Martin Ender – 2016-09-17T12:05:43.203

    You are right, only the opening one is enought, thanks – AxelH – 2016-09-17T12:16:59.507

    1

    C (gcc), 225 207 202 201 bytes

    Thanks to ceilingcat for -24 bytes

    #define P strcpy(f+d,index("!?.",i[c-2])+!c?
    c;d;v(i,g,f)char*i,*g,*f;{for(d=0;i[c];c++,d++)strcmp("[?]",memcpy(g,i+c,3))?f[d]=i[c]:(index("aeiouAEIOU",i[c+4])?P"An ":"an "),d++:P"A ":"a "),d++,c+=3);}
    

    Try it online!

    girobuz

    Posted 2016-09-15T03:10:31.813

    Reputation: 391

    1

    J, 113 bytes

    [:;:inv 3(0 2&{(((('aA'{~[)<@,'n'#~])~('.?!'e.~{:))~('AEIOUaeiou'e.~{.))&>/@[^:(<@'[?]'=])1{])\' 'cut' . '([,~,)]
    

    Try it online!

    Shame, shame!

    Jonah

    Posted 2016-09-15T03:10:31.813

    Reputation: 8 729

    1

    Retina, 66 60 bytes

    i`\[\?\]( ([aeiou]?)[a-z&&[^aeiou])
    a$.2*n$1
    (^|[.?!] )a
    $1A
    

    Try it online.

    Explanation:

    Do a case-insensitive search for [?] followed by a vowel or consonant, where the optional vowel is saved in capture group 2, and the entire match in capture group 1:

    i`\[\?\]( ([aeiou]?)[a-z&&[^aeiou])
    

    Replace this with an a, followed by the length of the second group amount of n (so either 0 or 1 n), followed by the letter(s) of capture group 1:

    a$.2*n$1
    

    Then match an a at either the start of the string, or after either of .?! plus a space:

    (^|[.?!] )a
    

    And uppercase that A, without removing the other characters of capture group 1:

    $1A
    

    Kevin Cruijssen

    Posted 2016-09-15T03:10:31.813

    Reputation: 67 575

    1

    Java (JDK), 154 bytes

    s->{String v="(?= [aeiou])",q="(?i)\\[\\?]",b="(?<=^|[?.!] )";return s.replaceAll(b+q+v,"An").replaceAll(q+v,"an").replaceAll(b+q,"A").replaceAll(q,"a");}
    

    Try it online!

    Explanation:

    s->{
        String v="(?= [aeiou])",          // matches being followed by a vowel
        q="(?i)\\[\\?]",                  // matches being a [?]
        b="(?<=^|[?.!] )";                // matches being preceded by a sentence beginning
        return s.replaceAll(b+q+v,"An")   // if beginning [?] vowel, you need "An"
            .replaceAll(q+v,"an")         // if           [?] vowel, you need "an"
            .replaceAll(b+q,"A")          // if beginning [?]      , you need "A"
            .replaceAll(q,"a");}          // if           [?]      , you need "a"
    

    Avi

    Posted 2016-09-15T03:10:31.813

    Reputation: 279

    1

    C#, 204 235 bytes

    string n(string b){for(int i=0;i<b.Length;i++){if(b[i]=='['){var r="a";r=i==0||b[i-2]=='.'?"A":r;r=System.Text.RegularExpressions.Regex.IsMatch(b[i+4].ToString(),@"[aeiouAEIOU]")?r+"n":r;b=b.Insert(i+3,r);}}return b.Replace("[?]","");}
    

    Ungolfed full program:

    using System;
    
    class a
    {
        static void Main()
        {
            string s = Console.ReadLine();
            a c = new a();
            Console.WriteLine(c.n(s));
        }
    
        string n(string b)
        {
            for (int i = 0; i < b.Length; i++)
            {
                if (b[i] == '[')
                {
                    var r = "a";
                    r = i == 0 || b[i - 2] == '.' ? "A" : r;
                    r = System.Text.RegularExpressions.Regex.IsMatch(b[i + 4].ToString(), @"[aeiouAEIOU]") ? r + "n" : r;
                    b = b.Insert(i + 3, r);
                }
            }
            return b.Replace("[?]", "");
        }
    }
    

    I'm sure this could be improved, especially the Regex part, but can't think of anything right now.

    Yodle

    Posted 2016-09-15T03:10:31.813

    Reputation: 2 378

    does it work without the imports? – cat – 2016-09-15T15:08:28.397

    Whoops, forgot to include the regex import in the count. – Yodle – 2016-09-15T17:00:11.290

    1The golfed code should run as-is in whatever format -- if it doesn't run without the regex import, then the regex import should go in the golfed code too – cat – 2016-09-15T20:53:46.033

    Okay, thanks. Still ironing out exactly how to answer. The count and answer include System.Text.RegularExpressions now. – Yodle – 2016-09-16T14:30:41.727

    This looks good now. :) You can also check out [meta] and the [meta-tag:faq] tag there. – cat – 2016-09-16T17:06:06.467

    1

    Racket 451 bytes (without regex)

    It is obviously a long answer but it replaces a and an with capitalization also:

    (define(lc sl item)(ormap(lambda(x)(equal? item x))sl))
    (define(lr l i)(list-ref l i))(define(f str)(define sl(string-split str))
    (for((i(length sl))#:when(equal?(lr sl i)"[?]"))(define o(if(lc(string->list"aeiouAEIOU")
    (string-ref(lr sl(add1 i))0))#t #f))(define p(if(or(= i 0)(lc(string->list".!?")
    (let((pr(lr sl(sub1 i))))(string-ref pr(sub1(string-length pr))))))#t #f))
    (set! sl(list-set sl i(if o(if p"An""an")(if p"A""a")))))(string-join sl))
    

    Testing:

    (f "[?] giant en le [?] sky.")
    (f "[?] yarn ball?")
    (f "[?] hour ago I met [?] European. ")
    (f "How about we build [?] big building. It will have [?] orange banana hanging out of [?] window.")
    (f "Hello, this is [?] world!")
    

    Output:

    "A giant en le a sky."
    "A yarn ball?"
    "A hour ago I met an European."
    "How about we build a big building. It will have an orange banana hanging out of a window."
    "Hello, this is a world!"
    

    Detailed version:

    (define(contains sl item)
      (ormap(lambda(x)(equal? item x))sl))
    
    (define(lr l i)
      (list-ref l i))
    
    (define(f str)
      (define sl(string-split str))
      (for((i(length sl))#:when(equal?(lr sl i)"[?]"))
        (define an   ; a or an
          (if(contains(string->list "aeiouAEIOU")
                      (string-ref(lr sl(add1 i))0))
             #t #f ))
        (define cap   ; capital or not
          (if(or(= i 0)(contains(string->list ".!?")
                                (let ((prev (lr sl(sub1 i)))) (string-ref prev
                                           (sub1(string-length prev))))))
             #t #f))
        (set! sl(list-set sl i (if an (if cap "An" "an" )
                                     (if cap "A" "a")))))
      (string-join sl))
    

    rnso

    Posted 2016-09-15T03:10:31.813

    Reputation: 1 635

    Yay for Racket! See also Tips for golfing in Racket / Scheme

    – cat – 2016-09-15T14:46:38.283

    It is an excellent language, though not meant for golfing. – rnso – 2016-09-15T14:53:21.813

    1

    Java 7, 239 214 213 bytes

    String c(String s){String x[]=s.split("\\[\\?\\]"),r="";int i=0,l=x.length-1;for(;i<l;r+=x[i]+(x[i].length()<1|x[i].matches(".+[.!?] $")?65:'a')+("aeiouAEIOU".contains(x[++i].charAt(1)+"")?"n":""));return r+x[l];}
    

    Ungolfed & test cases:

    Try it here.

    class M{
      static String c(String s){
        String x[] = s.split("\\[\\?\\]"),
               r = "";
        int i = 0,
            l = x.length - 1;
        for (; i < l; r += x[i]
                         + (x[i].length() < 1 | x[i].matches(".+[.!?] $") 
                            ? 65
                            : 'a')
                         + ("aeiouAEIOU".contains(x[++i].charAt(1)+"")
                            ? "n"
                            : ""));
        return r + x[l];
      }
    
      public static void main(String[] a){
        System.out.println(c("Hello, this is [?] world!"));
        System.out.println(c("How about we build [?] big building. It will have [?] orange banana hanging out of [?] window."));
        System.out.println(c("[?] giant en le sky."));
        System.out.println(c("[?] yarn ball? [?] big one!"));
        System.out.println(c("[?] hour ago I met [?] European. "));
        System.out.println(c("Hey sir [Richard], how 'bout [?] cat?"));
        System.out.println(c("[?] dog is barking. [?] cat is scared!"));
      }
    }
    

    Output:

    Hello, this is a world!
    How about we build a big building. It will have an orange banana hanging out of a window.
    A giant en le sky.
    A yarn ball? A big one!
    A hour ago I met an European. 
    Hey sir [Richard], how 'bout a cat?
    A dog is barking. A cat is scared!
    

    Kevin Cruijssen

    Posted 2016-09-15T03:10:31.813

    Reputation: 67 575

    I tried using a recursive solution, I end up with 2 bytes more then you :( need to improvement maybe .. but since I use your regex, I don't like to post it. – AxelH – 2016-09-16T14:39:09.107

    @AxelH Could you perhaps post it on ideone and link here? Together we might spot something to golf. ;) – Kevin Cruijssen – 2016-09-16T14:49:13.290

    Here is it https://ideone.com/z7hlVi, I did find a better approch thanisEmpty using the regex ^$. I believe I end up with 202 ;)

    – AxelH – 2016-09-16T20:36:43.467

    @AxelH Ah nice. Hmm, I count 195 bytes instead of 202? Btw, you can golf it to 180 by doing a direct return with a ternary if-else: String c(String s){String x[]=s.split("\\[\\?\\]",2),r=x[0];return x.length>1?r+(r.matches("(.+[.!?] )|(^)$")?"A":"a")+("aeiouAEIOU".contains(""+x[1].charAt(1))?"n":"")+c(x[1]):r;} So definitely shorter than my loop-answer. :) – Kevin Cruijssen – 2016-09-17T06:40:27.333

    Oh yeah, i manage to put the if bloc in one line at the end, forgot to replace it. Thanks; – AxelH – 2016-09-17T11:49:28.130

    0

    Python 3, 104 103 bytes

    -1 bytes, unescaped ]

    lambda s:r('(^|[.?!] )a',r'\1A',r('a( [aeiouAEIOU])',r'an\1',r('\[\?]','a',s)));from re import sub as r
    

    Try it online!

    Starts by replacing all occurences of [?] with a,
    Then replaces all a followed by a vowel, with an.
    Then replaces all a at the start of input or a sentence with A.

    Assumes that [?] will never be touching another word, and that lower-case a should never begin a sentence.

    Matthew Jensen

    Posted 2016-09-15T03:10:31.813

    Reputation: 713

    0

    PowerShell, 124 bytes

    inspired by Avi's answer for Java.

    $args-replace(($b='(?<=^|[?.!] )')+($q='\[\?]')+($v='(?= [aeiou])')),'An'-replace"$q$v",'an'-replace"$b$q",'A'-replace$q,'a'
    

    Try it online!

    mazzy

    Posted 2016-09-15T03:10:31.813

    Reputation: 4 832

    0

    Groovy, 73 162 bytes

    def a(s){s.replaceAll(/(?i)(?:(.)?( )?)\[\?\] (.)/){r->"${r[1]?:''}${r[2]?:''}${'.?!'.contains(r[1]?:'.')?'A':'a'}${'aAeEiIoOuU'.contains(r[3])?'n':''} ${r[3]}"}}
    

    edit: damn, the capitalization totally complicated everything here

    norganos

    Posted 2016-09-15T03:10:31.813

    Reputation: 51

    Does this capitalize at the beginning of a sentence? – Titus – 2016-09-15T12:05:32.857

    nope. I see now, that the challenge description has been changed in the meantime... – norganos – 2016-09-15T12:13:34.300

    "Give me [?] hour with [?] open cellar door." Breaks your code: https://groovyconsole.appspot.com/edit/5159915056267264

    – Magic Octopus Urn – 2016-09-15T12:21:06.237

    the challenge description still is completely inconsistent. first it says "You do have to worry about capitalization!" and directly after that there are the rules for capitalization – norganos – 2016-09-15T12:38:07.683

    It is consistent. You have to worry about capitalization (that is, you need to manage it). Then it explains how – edc65 – 2016-09-15T17:07:59.750

    yep, now i see, i was wrong. my subconsciousness must have added the "not" while reading – norganos – 2016-09-15T17:22:41.297

    0

    C# 209 bytes

    string A(string b){var s=b.Split(new[]{"[?]"},0);return s.Skip(1).Aggregate(s[0],(x,y)=>x+(x==""||(x.Last()==' '&&".?!".Contains(x.Trim().Last()))?"A":"a")+("AEIOUaeiou".Contains(y.Trim().First())?"n":"")+y);}

    Formatted

    string A(string b)
    {
        var s = b.Split(new[] { "[?]" }, 0);
        return s.Skip(1).Aggregate(s[0], (x, y) => x + (x == "" || (x.Last() == ' ' && ".?!".Contains(x.Trim().Last())) ? "A" : "a") + ("AEIOUaeiou".Contains(y.Trim().First()) ? "n" : "") + y);
    }
    

    Grax32

    Posted 2016-09-15T03:10:31.813

    Reputation: 1 282

    0

    Pip, 62 55 54 50 bytes

    Takes the string as a command-line argument.

    aR-`([^.?!] )?\[\?]( [^aeiou])?`{[b"aA"@!b'nX!cc]}
    

    Try it online!

    Explanation:

    a                                                   Cmdline argument
     R                                                  Replace...
      -`                           `                    The following regex (case-insensitive):
        ([^.?!] )?                                      Group 1: not end-of-sentence (nil if it doesn't match)
                  \[\?]                                 [?]
                       ( [^aeiou])?                     Group 2: not vowel (nil if there is a vowel)
                                    {                }  ... with this callback function (b = grp1, c = grp2):
                                     [              ]   List (concatenated when cast to string) of:
                                      b                 Group 1
                                       "aA"@!b          "a" if group 1 matched, else "A"
                                              'nX!c     "n" if group 2 didn't match, else ""
                                                   c    Group 2
    

    DLosc

    Posted 2016-09-15T03:10:31.813

    Reputation: 21 213

    0

    Perl 6, 78 bytes

    {S:i:g/(^|<[.?!]>' ')?'[?] '(<[aeiou]>?)/{$0 xx?$0}{<a A>[?$0]}{'n'x?~$1} $1/}
    

    Explanation:

    {
      S
        :ignorecase
        :global
      /
        ( # $0
        | ^             # beginning of line
        | <[.?!]> ' '   # or one of [.?!] followed by a space
        ) ?             # optionally ( $0 will be Nil if it doesn't match )
    
        '[?] '          # the thing to replace ( with trailing space )
    
        ( # $1
          <[aeiou]> ?   # optional vowel ( $1 will be '' if it doesn't match )
        )
    
      /{
        $0 xx ?$0      # list repeat $0 if $0
                       # ( so that it doesn't produce an error )
      }{
        < a A >[ ?$0 ] # 'A' if $0 exists, otherwise 'a'
      }{
        'n' x ?~$1     # 'n' if $1 isn't empty
                       # 「~」 turns the Match into a Str
                       # 「?」 turns that Str into a Bool
                       # 「x」 string repeat the left side by the amount of the right
    
      # a space and the vowel we may have borrowed
      } $1/
    }
    

    Test:

    #! /usr/bin/env perl6
    use v6.c;
    use Test;
    
    my &code = {S:i:g/(^|<[.?!]>' ')?'[?] '(<[aeiou]>?)/{<a A>[?$0]~('n'x?~$1)} $1/}
    
    my @tests = (
      'Hello, this is [?] world!'
      => 'Hello, this is a world!',
    
      'How about we build [?] big building. It will have [?] orange banana hanging out of [?] window.'
      => 'How about we build a big building. It will have an orange banana hanging out of a window.',
    
      '[?] giant en le sky.'
      => 'A giant en le sky.',
    
      '[?] yarn ball?'
      => 'A yarn ball?',
    
      '[?] hour ago I met [?] European.'
      => 'A hour ago I met an European.',
    
      "Hey sir [Richard], how 'bout [?] cat?"
      => "Hey sir [Richard], how 'bout a cat?",
    );
    
    plan +@tests;
    
    for @tests -> $_ ( :key($input), :value($expected) ) {
      is code($input), $expected, $input.perl;
    }
    
    1..6
    ok 1 - "Hello, this is a world!"
    ok 2 - "How about we build a big building. It will have an orange banana hanging out of a window."
    ok 3 - "A giant en le sky."
    ok 4 - "A yarn ball?"
    ok 5 - "A hour ago I met an European."
    ok 6 - "Hey sir [Richard], how 'bout a cat?"
    

    Brad Gilbert b2gills

    Posted 2016-09-15T03:10:31.813

    Reputation: 12 713

    Can you remove a space from } $1 at the end (making it }$1)? – Cyoce – 2016-09-16T17:02:12.403

    @Cyoce There is a way of doing that, but it adds more complexity elsewhere. {S:i:g/(^|<[.?!]>' ')?'[?]'(' '<[aeiou]>?)/{<a A>[?$0]~('n'x?~$1.substr(1))}$1/} – Brad Gilbert b2gills – 2016-09-16T17:29:39.883

    Ok, I wasn't sure how perl would parse that – Cyoce – 2016-09-16T18:06:59.363

    0

    Lua, 131 Bytes.

    function(s)return s:gsub("%[%?%](%s*.)",function(a)return"a"..(a:find("[AEIOUaeiou]")and"n"or"")..a end):gsub("^.",string.upper)end
    

    Although lua is a terrible Language for golfing, I feel I've done pretty well.

    ATaco

    Posted 2016-09-15T03:10:31.813

    Reputation: 7 898

    0

    Racket (with regex) 228 bytes

    (define(r a b c)(regexp-replace* a b c))
    (define(f s)
    (set! s(r #rx"[a-zA-Z ]\\[\\?\\] (?=[aeiouAEIOU])"s" an "))
    (set! s(r #rx"[a-zA-Z ]\\[\\?\\]"s" a"))
    (set! s(r #rx"\\[\\?\\] (?=[aeiouAEIOU])"s"An "))
    (r #rx"\\[\\?\\]"s"A"))
    

    Testing:

    (f "[?] giant en le [?] sky.")
    (f "[?] yarn ball?")
    (f "[?] apple?")
    (f "[?] hour ago I met [?] European. ")
    (f "How about we build [?] big building. It will have [?] orange banana hanging out of [?] window.")
    (f "Hello, this is [?] world!")
    

    Output:

    "A giant en le a sky."
    "A yarn ball?"
    "An apple?"
    "A hour ago I met an European. "
    "How about we build a big building. It will have an orange banana hanging out of a window."
    "Hello, this is a world!"
    

    rnso

    Posted 2016-09-15T03:10:31.813

    Reputation: 1 635