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.


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.


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.


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!

  • \$\begingroup\$ OK thanks. Can we assume no inputs will have extra spaces between the [?] and the word? \$\endgroup\$ – DJMcMayhem Sep 15 '16 at 3:20
  • 8
    \$\begingroup\$ Does 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. \$\endgroup\$ – DLosc Sep 15 '16 at 4:25
  • 1
    \$\begingroup\$ Could you please clarify when to capitalize? The first character? \$\endgroup\$ – DJMcMayhem Sep 15 '16 at 4:50
  • 34
    \$\begingroup\$ You should add the test case [?] hour ago I met [?] European. just to make everyone cringe. \$\endgroup\$ – Martin Ender Sep 15 '16 at 9:03
  • 1
    \$\begingroup\$ Now we must have [?] hour ago I met [?] horse. \$\endgroup\$ – beaker Sep 15 '16 at 15:39

26 Answers 26


V, 41 bytes

ÍãÛ?Ý ¨[aeiou]©/an
Í^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
  • \$\begingroup\$ Unfortunately, OP said "You do have to worry about capitalization!" (emphasis mine). \$\endgroup\$ – El'endia Starman Sep 15 '16 at 4:43
  • 1
    \$\begingroup\$ @El'endiaStarman Oh I misread that. I can fix it, but I have no clue what to capitalize, since OP didn't specify. \$\endgroup\$ – DJMcMayhem Sep 15 '16 at 4:54
  • \$\begingroup\$ @El'endiaStarman Fixed now. \$\endgroup\$ – DJMcMayhem Sep 15 '16 at 16:22

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.


#!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.
  • 2
    \$\begingroup\$ Could you explain this, please? \$\endgroup\$ – sudee Sep 15 '16 at 7:30
  • 1
    \$\begingroup\$ Support for capitalization after /[.?!]/ followed by space is missing \$\endgroup\$ – Ton Hospel Sep 15 '16 at 13:33
  • 1
    \$\begingroup\$ @TonHospel 10 hours ago, the problem made no mention of this. \$\endgroup\$ – primo Sep 15 '16 at 15:30
  • 2
    \$\begingroup\$ Ok, 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 \$\endgroup\$ – Ton Hospel Sep 15 '16 at 15:50
  • 1
    \$\begingroup\$ @sudee updated to include explanation. \$\endgroup\$ – primo Sep 16 '16 at 1:23

Ruby, 78 72 bytes

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


def f(s)
    s.gsub(/(^|\. )?\[\?\]( [aeiou])?/i) do |m|
        capitalize = $1
        vowel = $2
        replacement = if vowel then
            capitalize ? "An" : "an"
            capitalize ? "A" : "a"
        m.sub('[?]', replacement)
  • 2
    \$\begingroup\$ "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"} \$\endgroup\$ – Jordan Sep 15 '16 at 13:43

PHP, 207 bytes


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!


        // lookbehind: uppercase if the end of a sentence precedes
        // lookahead: append "n" if a vowel follows (consider quote characters blank)
    // output replacement and this part
    // 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:".");`
  • 3
    \$\begingroup\$ Upvote for "banana shortage"! LOL \$\endgroup\$ – MonkeyZeus Sep 15 '16 at 14:57
  • \$\begingroup\$ @MonkeyZeus: Try [?][?][?]s [?]lert! \$\endgroup\$ – Titus Sep 15 '16 at 16:58
  • \$\begingroup\$ All I can imagine is a heartbroken Donkey Kong worried sick about the shortage now :( \$\endgroup\$ – MonkeyZeus Sep 15 '16 at 18:09

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!


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.

  • 6
    \$\begingroup\$ Am I the only one who wants to go play excitebike after reading that explanation? \$\endgroup\$ – Magic Octopus Urn Sep 15 '16 at 12:17

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))


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 

#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>

  • \$\begingroup\$ Shouldn't [?][?] give Ana? And shouldn't [?][?] a. produce Ana a.? \$\endgroup\$ – Ismael Miguel Sep 15 '16 at 9:05
  • \$\begingroup\$ @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. \$\endgroup\$ – edc65 Sep 15 '16 at 9:07
  • \$\begingroup\$ Got it, but your code is giving weird results for [?] "[?]". (An "A", the quotes are irrelevant) and for [?] "A". (it works fine for [?] A.). \$\endgroup\$ – Ismael Miguel Sep 15 '16 at 9:29
  • \$\begingroup\$ @IsmaelMiguel [?] "[?]" is not valid input. [?] will always appear before a word and "[?]" is not a word. \$\endgroup\$ – edc65 Sep 15 '16 at 9:37
  • 2
    \$\begingroup\$ The escaping of second ] is not need. /(\w )?\[\?](\W*.)/g \$\endgroup\$ – Huntro Sep 15 '16 at 10:37

Batch, 136 bytes

@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.


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

  • \$\begingroup\$ It should also be possible to get your replacement array down to [n,A,a] by using look-around assertions (\K and (?= )). \$\endgroup\$ – primo Sep 15 '16 at 16:38

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 !

  • 1
    \$\begingroup\$ Welcome to PPCG! I don't think you need to escape the ] in your regex. \$\endgroup\$ – Martin Ender Sep 17 '16 at 12:05
  • \$\begingroup\$ You are right, only the opening one is enought, thanks \$\endgroup\$ – AxelH Sep 17 '16 at 12:16

05AB1E, 38 36 35 bytes


Try it online or verify all test cases.


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)
  • 1
    \$\begingroup\$ There'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 :: \$\endgroup\$ – Dorian Oct 1 '19 at 15:25
  • \$\begingroup\$ @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! \$\endgroup\$ – Kevin Cruijssen Oct 1 '19 at 15:29

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!

  • 1
    \$\begingroup\$ Welcome to Codegolf. You could use ; and golf it. \$\endgroup\$ – ABcDexter Sep 15 '16 at 11:09
  • 1
    \$\begingroup\$ m.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. \$\endgroup\$ – Erik the Outgolfer Sep 15 '16 at 11:42
  • 1
    \$\begingroup\$ ('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. \$\endgroup\$ – Rod Sep 15 '16 at 11:54
  • 1
    \$\begingroup\$ This community is so lovely, seeing how many people are willing to help a newcomer and provide golfing tips! \$\endgroup\$ – yo' Sep 15 '16 at 15:41
  • 1
    \$\begingroup\$ Wow enumerate() is cool. Thanks @chepner. \$\endgroup\$ – Gurupad Mamadapur Sep 15 '16 at 16:17

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();

    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.

  • \$\begingroup\$ does it work without the imports? \$\endgroup\$ – cat Sep 15 '16 at 15:08
  • \$\begingroup\$ Whoops, forgot to include the regex import in the count. \$\endgroup\$ – Yodle Sep 15 '16 at 17:00
  • 1
    \$\begingroup\$ The 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 \$\endgroup\$ – cat Sep 15 '16 at 20:53
  • \$\begingroup\$ Okay, thanks. Still ironing out exactly how to answer. The count and answer include System.Text.RegularExpressions now. \$\endgroup\$ – Yodle Sep 16 '16 at 14:30
  • \$\begingroup\$ This looks good now. :) You can also check out Code Golf Meta and the faq tag there. \$\endgroup\$ – cat Sep 16 '16 at 17:06

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!"));


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!
  • \$\begingroup\$ 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. \$\endgroup\$ – AxelH Sep 16 '16 at 14:39
  • \$\begingroup\$ @AxelH Could you perhaps post it on ideone and link here? Together we might spot something to golf. ;) \$\endgroup\$ – Kevin Cruijssen Sep 16 '16 at 14:49
  • \$\begingroup\$ Here is it ideone.com/z7hlVi, I did find a better approch thanisEmpty using the regex ^$. I believe I end up with 202 ;) \$\endgroup\$ – AxelH Sep 16 '16 at 20:36
  • \$\begingroup\$ @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. :) \$\endgroup\$ – Kevin Cruijssen Sep 17 '16 at 6:40
  • \$\begingroup\$ Oh yeah, i manage to put the if bloc in one line at the end, forgot to replace it. Thanks; \$\endgroup\$ – AxelH Sep 17 '16 at 11:49

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))


(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!")


"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))
  • \$\begingroup\$ Yay for Racket! See also Tips for golfing in Racket / Scheme \$\endgroup\$ – cat Sep 15 '16 at 14:46
  • \$\begingroup\$ It is an excellent language, though not meant for golfing. \$\endgroup\$ – rnso Sep 15 '16 at 14:53

J, 113 bytes

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

Try it online!

Shame, shame!


Retina, 66 60 bytes

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

Try it online.


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:


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:


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!


    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"

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!


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

  • \$\begingroup\$ Does this capitalize at the beginning of a sentence? \$\endgroup\$ – Titus Sep 15 '16 at 12:05
  • \$\begingroup\$ nope. I see now, that the challenge description has been changed in the meantime... \$\endgroup\$ – norganos Sep 15 '16 at 12:13
  • \$\begingroup\$ "Give me [?] hour with [?] open cellar door." Breaks your code: groovyconsole.appspot.com/edit/5159915056267264 \$\endgroup\$ – Magic Octopus Urn Sep 15 '16 at 12:21
  • \$\begingroup\$ 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 \$\endgroup\$ – norganos Sep 15 '16 at 12:38
  • \$\begingroup\$ It is consistent. You have to worry about capitalization (that is, you need to manage it). Then it explains how \$\endgroup\$ – edc65 Sep 15 '16 at 17:07

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);}


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);

Perl 6, 78 bytes

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


    ( # $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/


#! /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;
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?"
  • \$\begingroup\$ Can you remove a space from } $1 at the end (making it }$1)? \$\endgroup\$ – Cyoce Sep 16 '16 at 17:02
  • \$\begingroup\$ @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/} \$\endgroup\$ – Brad Gilbert b2gills Sep 16 '16 at 17:29
  • \$\begingroup\$ Ok, I wasn't sure how perl would parse that \$\endgroup\$ – Cyoce Sep 16 '16 at 18:06

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.


Pip, 62 55 54 50 bytes

Takes the string as a command-line argument.

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

Try it online!


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

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"))


(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!")


"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!"

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.


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!


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.