22
\$\begingroup\$

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!

\$\endgroup\$
15
  • \$\begingroup\$ OK thanks. Can we assume no inputs will have extra spaces between the [?] and the word? \$\endgroup\$ Commented Sep 15, 2016 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\$ Commented Sep 15, 2016 at 4:25
  • 1
    \$\begingroup\$ Could you please clarify when to capitalize? The first character? \$\endgroup\$ Commented Sep 15, 2016 at 4:50
  • 36
    \$\begingroup\$ You should add the test case [?] hour ago I met [?] European. just to make everyone cringe. \$\endgroup\$ Commented Sep 15, 2016 at 9:03
  • 2
    \$\begingroup\$ Now we must have [?] hour ago I met [?] horse. \$\endgroup\$ Commented Sep 15, 2016 at 15:39

26 Answers 26

7
\$\begingroup\$

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

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 
\$\endgroup\$
1
  • 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\$ Commented Sep 15, 2016 at 13:43
6
\$\begingroup\$

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 
\$\endgroup\$
3
  • \$\begingroup\$ Unfortunately, OP said "You do have to worry about capitalization!" (emphasis mine). \$\endgroup\$ Commented Sep 15, 2016 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\$ Commented Sep 15, 2016 at 4:54
  • \$\begingroup\$ @El'endiaStarman Fixed now. \$\endgroup\$ Commented Sep 15, 2016 at 16:22
6
\$\begingroup\$

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:".");` } 
\$\endgroup\$
3
  • 3
    \$\begingroup\$ Upvote for "banana shortage"! LOL \$\endgroup\$ Commented Sep 15, 2016 at 14:57
  • \$\begingroup\$ @MonkeyZeus: Try [?][?][?]s [?]lert! \$\endgroup\$ Commented Sep 15, 2016 at 16:58
  • \$\begingroup\$ All I can imagine is a heartbroken Donkey Kong worried sick about the shortage now :( \$\endgroup\$ Commented Sep 15, 2016 at 18:09
5
\$\begingroup\$

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.

\$\endgroup\$
1
  • 6
    \$\begingroup\$ Am I the only one who wants to go play excitebike after reading that explanation? \$\endgroup\$ Commented Sep 15, 2016 at 12:17
4
\$\begingroup\$

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>

\$\endgroup\$
12
  • \$\begingroup\$ Shouldn't [?][?] give Ana? And shouldn't [?][?] a. produce Ana a.? \$\endgroup\$ Commented Sep 15, 2016 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\$ Commented Sep 15, 2016 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\$ Commented Sep 15, 2016 at 9:29
  • \$\begingroup\$ @IsmaelMiguel [?] "[?]" is not valid input. [?] will always appear before a word and "[?]" is not a word. \$\endgroup\$ Commented Sep 15, 2016 at 9:37
  • 2
    \$\begingroup\$ The escaping of second ] is not need. /(\w )?\[\?](\W*.)/g \$\endgroup\$ Commented Sep 15, 2016 at 10:37
2
\$\begingroup\$

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.

\$\endgroup\$
2
\$\begingroup\$

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

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

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 !

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

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) 
\$\endgroup\$
2
  • 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\$ Commented Oct 1, 2019 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\$ Commented Oct 1, 2019 at 15:29
2
\$\begingroup\$

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!

\$\endgroup\$
12
  • 1
    \$\begingroup\$ Welcome to Codegolf. You could use ; and golf it. \$\endgroup\$ Commented Sep 15, 2016 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\$ Commented Sep 15, 2016 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\$ Commented Sep 15, 2016 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\$ Commented Sep 15, 2016 at 15:41
  • 1
    \$\begingroup\$ Wow enumerate() is cool. Thanks @chepner. \$\endgroup\$ Commented Sep 15, 2016 at 16:17
1
\$\begingroup\$

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.

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

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! 
\$\endgroup\$
5
  • \$\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\$ Commented Sep 16, 2016 at 14:39
  • \$\begingroup\$ @AxelH Could you perhaps post it on ideone and link here? Together we might spot something to golf. ;) \$\endgroup\$ Commented Sep 16, 2016 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\$ Commented Sep 16, 2016 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\$ Commented Sep 17, 2016 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\$ Commented Sep 17, 2016 at 11:49
1
\$\begingroup\$

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

J, 113 bytes

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

Try it online!

Shame, shame!

\$\endgroup\$
1
\$\begingroup\$

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 
\$\endgroup\$
1
\$\begingroup\$

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" 
\$\endgroup\$
1
\$\begingroup\$

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!

\$\endgroup\$
0
0
\$\begingroup\$

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

\$\endgroup\$
6
  • \$\begingroup\$ Does this capitalize at the beginning of a sentence? \$\endgroup\$ Commented Sep 15, 2016 at 12:05
  • \$\begingroup\$ nope. I see now, that the challenge description has been changed in the meantime... \$\endgroup\$ Commented Sep 15, 2016 at 12:13
  • \$\begingroup\$ "Give me [?] hour with [?] open cellar door." Breaks your code: groovyconsole.appspot.com/edit/5159915056267264 \$\endgroup\$ Commented Sep 15, 2016 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\$ Commented Sep 15, 2016 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\$ Commented Sep 15, 2016 at 17:07
0
\$\begingroup\$

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); } 
\$\endgroup\$
0
\$\begingroup\$

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?" 
\$\endgroup\$
3
  • \$\begingroup\$ Can you remove a space from } $1 at the end (making it }$1)? \$\endgroup\$ Commented Sep 16, 2016 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\$ Commented Sep 16, 2016 at 17:29
  • \$\begingroup\$ Ok, I wasn't sure how perl would parse that \$\endgroup\$ Commented Sep 16, 2016 at 18:06
0
\$\begingroup\$

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.

\$\endgroup\$
0
\$\begingroup\$

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 
\$\endgroup\$
0
\$\begingroup\$

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!" 
\$\endgroup\$
0
\$\begingroup\$

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.

\$\endgroup\$
0
\$\begingroup\$

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!

\$\endgroup\$

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.