19
\$\begingroup\$

This is similar to Making an acronym, but there are several key differences, including the method of fetching the acronym, and this challenge including flexible output.

Task

Given a string (list of chars/length 1 strings is allowed) containing only printable ASCII, output all capital letters in the input that are either preceded by a space or a dash, or are the first character in the input. Empty string is undefined behavior.

Test Cases:

Output may be in the format of "TEST", ["T","E","S","T"], or whatever else works for you.

Self-contained Underwater Breathing Apparatus
SUBA

a Programming Language
PL

NATO Atlantic TREATY Organization
NATO

DEFCON 2
D

hello, world!


light-Emitting dioDe
E

What Does the Fox Say?
WDFS


3D mov-Ies
I

laugh-Out Lou-D
OLD

Best friends FOREVE-r
BF

--


<space>


--  --a -  - --


--  -- -  - -- A
A

Step-Hen@Gmail-Mail Mail.CoM m
SHMM

This is , so shortest answer in bytes wins.

\$\endgroup\$
  • \$\begingroup\$ Sandbox \$\endgroup\$ – Stephen Jul 21 '17 at 13:21
  • \$\begingroup\$ Can we take input as a list of Strings (list of characters)? \$\endgroup\$ – Mr. Xcoder Jul 21 '17 at 13:43
  • \$\begingroup\$ @Mr.Xcoder yes. \$\endgroup\$ – Stephen Jul 21 '17 at 13:45
  • \$\begingroup\$ Could you add a test case that includes some letters separated by one or more characters that aren't letters, numbers, spaces or dashes. An e-mail address, for example: My-Name@Some-Domain.TLD. \$\endgroup\$ – Shaggy Jul 21 '17 at 16:12
  • 1
    \$\begingroup\$ @Shaggy added, thanks. \$\endgroup\$ – Stephen Jul 21 '17 at 17:10

34 Answers 34

8
\$\begingroup\$

V, 7 bytes

ÍÕü¼À!õ

Try it online!

Here is a hexdump to prove the byte count:

00000000: cdd5 fcbc c021 f5                        .....!.

Explanation:

Í       " Search and replace all occurrences on all lines:
        " (Search for)
 Õ      "   A non-uppercase letter [^A-Z]
  ü     "   OR
      õ "   An uppercase letter
    À!  "   Not preceded by...
   ¼    "   A word-boundary
        " (implicitly) And replace it with:
        "   Nothing

This is short all thanks to V's wonderful regex compression.

\$\endgroup\$
  • \$\begingroup\$ That's pretty short 0.o \$\endgroup\$ – Stephen Jul 21 '17 at 14:57
  • \$\begingroup\$ @StepHen Why thank you! I think this is pretty close to optimal. :) \$\endgroup\$ – DJMcMayhem Jul 21 '17 at 14:58
  • 2
    \$\begingroup\$ What do you mean by a word boundary? The question seems to suggest that only space and - are allowed. \$\endgroup\$ – Neil Jul 21 '17 at 15:44
8
\$\begingroup\$

R, 66 63 bytes

function(s)(s=substr(strsplit(s,' |-')[[1]],1,1))[s%in%LETTERS]

Try it online!

-3 bytes thanks to Scarabee

An anonymous function; returns the acronym as a vector c("N","A","T","O") which is implicitly printed.

For once, this isn't too bad in R! splits on - or (space), takes the first element of each of those, and then returns whichever ones are capitals (LETTERS is an R builtin with the capital letters), in order.

\$\endgroup\$
  • \$\begingroup\$ I think you can save a few bytes: function(s)(s=substr(strsplit(s,' |-')[[1]],1,1))[s%in%LETTERS] \$\endgroup\$ – Scarabee Jul 23 '17 at 0:00
  • 1
    \$\begingroup\$ @Scarabee thank you. sorry it took 2 years to update. \$\endgroup\$ – Giuseppe Jul 18 at 16:09
6
\$\begingroup\$

Python 2, 59 56 bytes

-3 bytes thanks to Lynn

lambda s:[b for a,b in zip(' '+s,s)if'@'<b<'['>a in' -']

Try it online!

\$\endgroup\$
  • \$\begingroup\$ I borrowed your trick '@'<b<'[', very nice solution +1 \$\endgroup\$ – Mr. Xcoder Jul 21 '17 at 13:36
  • \$\begingroup\$ Don’t forget about comparison chaining! '@'<b<'['>a in' -' saves 3 bytes. \$\endgroup\$ – Lynn Jul 21 '17 at 14:50
5
\$\begingroup\$

Javascript 21 bytes

Takes a string input and outputs an array of strings containing the acronym characters

x=>x.match(/\b[A-Z]/g)

Explanation

It's just a global regex match for word-boundary followed by a capital letter.

\$\endgroup\$
4
\$\begingroup\$

Retina, 21 17 bytes

!`(?<=^| |-)[A-Z]

Try it online!

Explanation

Outputs the matches of the regex (?<=^| |-)[A-Z] in the input, one per line (!).

\$\endgroup\$
4
\$\begingroup\$

Dyalog APL, 29 23 bytes

Bonus test case: A Programming Language (APL).

'(?<=^| |-)[A-Z]'⎕S'&'⊢

Returns an array of chars (shows as space seperated on TIO).

Try it online!


Older post, 29 bytes

{(⎕AV~⎕A)~⍨'(\w)\w+'⎕R'\1'⊢⍵}

Try it online!

How?

'(\w)\w+'⎕R - replace each cluster of alphabetic chars

    '\1' - with its first character

~⍨ - remove every char

    (⎕AV~⎕A) - that is not an ASCII uppercase

\$\endgroup\$
3
\$\begingroup\$

Python, 53 bytes

import re
lambda s:re.findall("(?<=[ -])[A-Z]"," "+s)

Try it online!

A simple regular expression with a lookahead for space or dash. Rather than matching the start, prepend a space.

\$\endgroup\$
  • \$\begingroup\$ Edited in a TIO link with MrXCoder's test suite. \$\endgroup\$ – Stephen Jul 21 '17 at 13:54
  • \$\begingroup\$ Thanks @StepHen -- you beat me to it and saved me the effort \$\endgroup\$ – Chris H Jul 21 '17 at 13:55
  • \$\begingroup\$ 50 \$\endgroup\$ – negative seven Jul 18 at 14:55
3
\$\begingroup\$

C#, 84 78 bytes

using System.Linq;s=>s.Where((c,i)=>c>64&c<91&(i>0?s[i-1]==32|s[i-1]==45:1>0))

Saved 6 bytes thanks to @jkelm.

Try it online!

Full/Formatted Version:

using System.Collections.Generic;
using System.Linq;

class P
{
    static void Main()
    {
        System.Func<string, IEnumerable<char>> f = s => s.Where((c, i) => c > 64 & c < 91 & (i > 0 ? s[i-1] == 32 | s[i-1] == 45: 1 > 0));

        System.Console.WriteLine(string.Concat(f("Self-contained Underwater Breathing Apparatus")));
        System.Console.WriteLine(string.Concat(f("a Programming Language")));
        System.Console.WriteLine(string.Concat(f("NATO Atlantic TREATY Organization")));
        System.Console.WriteLine(string.Concat(f("DEFCON 2")));
        System.Console.WriteLine(string.Concat(f("hello, world!")));
        System.Console.WriteLine(string.Concat(f("light-Emitting dioDe")));
        System.Console.WriteLine(string.Concat(f("What Does the Fox Say?")));
        System.Console.WriteLine(string.Concat(f("3D mov-Ies")));
        System.Console.WriteLine(string.Concat(f("laugh-Out Lou-D")));
        System.Console.WriteLine(string.Concat(f("Best friends FOREVE-r")));
        System.Console.WriteLine(string.Concat(f(" ")));
        System.Console.WriteLine(string.Concat(f("--  --a -  - --")));
        System.Console.WriteLine(string.Concat(f("--  -- -  - -- A")));

        System.Console.ReadLine();
    }
}
\$\endgroup\$
  • \$\begingroup\$ Why do you have to include using System.Linq in the byte count if using System.Collections.Generic is exempt? Is there some consensus on which using's are countable? \$\endgroup\$ – user20151 Jul 21 '17 at 14:04
  • \$\begingroup\$ @DaveParsons using System.Linq; is needed for the Linq code in my answer. However, IEnumerbale<char> is not part of the answer and that is the part of the code that needs using System.Collections.Generic; to compile. \$\endgroup\$ – TheLethalCoder Jul 21 '17 at 14:05
  • \$\begingroup\$ makes sense; thanks for clarification. \$\endgroup\$ – user20151 Jul 21 '17 at 14:08
  • \$\begingroup\$ You could save a few bytes by checking uppercase using the chars as ints. c>64&c<91 should net you 6 bytes. \$\endgroup\$ – jkelm Jul 21 '17 at 14:47
  • \$\begingroup\$ @jkelm Nice :) I always forget about that trick! \$\endgroup\$ – TheLethalCoder Jul 21 '17 at 14:49
3
\$\begingroup\$

Julia 0.6.0 (57 bytes)

s=split(s,r" |-");for w∈s isupper(w[1])&&print(w[1])end

Explanation: This is my first code-golf. Pretty straight forward. Split the words, print 1rst upper letter of each.

Probably easy to do better using regex but I am new to this

\$\endgroup\$
  • 1
    \$\begingroup\$ Welcome to PPCG! I'm out of votes right now, I'll upvote this later. \$\endgroup\$ – Stephen Jul 21 '17 at 20:40
  • 2
    \$\begingroup\$ @StepHen I've gotchoo covered. :P \$\endgroup\$ – DJMcMayhem Jul 21 '17 at 20:42
2
\$\begingroup\$

05AB1E, 11 bytes

'-ð‡ð¡ζнAuÃ

Try it online!

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

C# (.NET Core), 108 bytes

n=>{var j="";n=' '+n;for(int i=0;++i<n.Length;)if(" -".IndexOf(n[i-1])>=0&n[i]>64&n[i]<91)j+=n[i];return j;}

Try it online!

\$\endgroup\$
  • \$\begingroup\$ Haven't checked but changing the if to a ternary might save you bytes. This starts at index 2 instead of 1, just change int i=1 to int i=0 to fix it. Other than that I don't think there's much more you can do here. \$\endgroup\$ – TheLethalCoder Jul 21 '17 at 15:00
  • \$\begingroup\$ A ternary wouldn't help here, as it would be the same byte count as an if statement. However, you are correct in that I need to change the initial i value \$\endgroup\$ – jkelm Jul 21 '17 at 15:11
  • \$\begingroup\$ I wasn't entirely sure but they usually come out shorter so it is always worth a check. \$\endgroup\$ – TheLethalCoder Jul 21 '17 at 15:12
2
\$\begingroup\$

Jelly,  11  10 bytes

-1 byte thanks to Erik the Outgolfer ( splits at spaces >_<)

⁾- yḲḢ€fØA

A monadic link taking and returning lists of characters.
As a full program accepts a string and prints the result.

Try it online! or see a test suite.

How?

⁾- yḲḢ€fØA - Link: list of characters, x       e.g. "Pro-Am Code-golf Association"
   y       - translate x with:
⁾-         -   literal list of characters ['-',' '] "Pro Am Code golf Association"
    Ḳ      - split at spaces               ["Pro","Am","Code","golf","Association"]
     Ḣ€    - head each (1st character of each)      "PACgA"
        ØA - yield uppercase alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
       f   - filter keep                            "PACA"
           - if running as a full program: implicit print
\$\endgroup\$
  • \$\begingroup\$ Umm, why not use instead of ṣ⁶? \$\endgroup\$ – Erik the Outgolfer Jul 21 '17 at 14:43
  • \$\begingroup\$ Heh, because I forgot about it. Thanks! \$\endgroup\$ – Jonathan Allan Jul 21 '17 at 14:44
2
\$\begingroup\$

Perl 5, 25 bytes

24 bytes code + 1 for -n.

Annoying that grep -P support variable length look-behind but Perl doesn't :(.

print/(?:^| |-)([A-Z])/g

-1 byte thanks to @Dada!

Try it online! - includes -l to run all tests at once.

\$\endgroup\$
  • \$\begingroup\$ You can do extremely way much so better: Try it online! ;-) \$\endgroup\$ – Dada Jul 27 '17 at 11:44
  • \$\begingroup\$ @Dada Hah! Of course... I'm out ATM but I'll update when I get back. Thanks! I'm quite disappointed I couldn't get s/// or $_= to negate the print... \$\endgroup\$ – Dom Hastings Jul 27 '17 at 11:50
  • \$\begingroup\$ Yeah, I was looking for a single s/// to solve this but it's not obvious... I'm at work, maybe I'll give it another try later! \$\endgroup\$ – Dada Jul 27 '17 at 11:53
2
\$\begingroup\$

MATL, 19 bytes

'- 'X{&Yb'^[A-Z]'XX

Try it online!

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

Brachylog, 25 23 22 bytes

,Ṣ↻s₂ᶠ{h∈" -"&t.∧Ạụ∋}ˢ

Try it online!

(-2 bytes thanks to @Fatalize.)

,Ṣ↻                      % prepend a space to input
   s₂ᶠ                   % get all substrings of length 2 from that, to get prefix-character pairs
      {              }ˢ  % get the successful outputs from this predicate: 
       h∈" -"              % the prefix is - or space
               &t.∧        % then the character is the output of this predicate if:
                  Ạụ∋        % the alphabet uppercased contains the character
\$\endgroup\$
  • \$\begingroup\$ You can use instead of " " to save two bytes \$\endgroup\$ – Fatalize Jul 30 '18 at 6:41
2
\$\begingroup\$

Japt, 19 16 14 bytes

-2 bytes thanks to Shaggy

f/^| |-)\A/ mÌ

Try it online!

\$\endgroup\$
  • \$\begingroup\$ Since you're using v2, I think you can change "(^| |-)%A" to /^| |-)\A/ to save a byte \$\endgroup\$ – ETHproductions Jul 21 '17 at 19:51
  • 1
    \$\begingroup\$ mf\A -> to save 2 bytes. \$\endgroup\$ – Shaggy Jan 4 at 15:55
2
\$\begingroup\$

Swift 5, 110 bytes

-5 thanks to Cœur

import UIKit
func f(s:[String]){for i in zip(s,[" "]+s){if i.0.isUppercase()&&"- ".contains(i.1){print(i.0)}}}

Detailed Explanation

  • import Foundation - Imports the module Foundation that is vital for zip(), the main piece of this code.

  • func f(s:[String]){...} - Creates a function with a parameter s, that is a list of Strings, representing the characters of the input.

  • for i in zip(s,[" "]+s){...} - Iterates with i through the zip of the input and the input with a space added in the beginning, which is very helpful for getting the previous character in the String.

  • if - Checks whether:

    • i.0==i.0.uppercased() - The current character is uppercase,

    • &&"- ".contains(i.1) - and If the previous character is a space or a dash.

  • If the above conditions are met, then:

    • print(i.0) - The character is printed, because it is part of the acronym.
\$\endgroup\$
  • \$\begingroup\$ -5 with import UIKit instead of import Foundation. \$\endgroup\$ – Cœur Jul 18 at 13:45
2
\$\begingroup\$

PowerShell, 43 bytes

''+($args|sls '(?<=^| |-)[A-Z]'-a -ca|% m*)

Try it online!

Unrolled:

''+($args|select-string '(?<=^| |-)[A-Z]' -allmatches -caseSensitive|% matches)
\$\endgroup\$
2
\$\begingroup\$

Python 3, 67 bytes

lambda x:[c[0]for c in x.replace("-"," ").split()if c[0].isupper()]

Try it online!

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

Python 3, 73 70 bytes

lambda n:[n[x]for x in range(len(n))if'@'<n[x]<'['and(' '+n)[x]in' -']

Try it online!


Explanation

  • lambda n: - Creates an anonymous lambda-function with a String parameter n.

  • n[x] - Gets the character of n at index x.

  • for x in range(len(n)) - Iterates from 0 to the length of n, naming the variable x.

  • if - Checks:

    • '@'<n[x]<'[' - If the character is uppercase,

    • and(' '+n)[x]in' -' - And if it is preceded by a space or a dash in the String formed by a space and n.

\$\endgroup\$
  • 2
    \$\begingroup\$ Is it bad that I read that as i supper, and I have no idea why? \$\endgroup\$ – TheLethalCoder Jul 21 '17 at 13:22
  • \$\begingroup\$ @TheLethalCoder It's .isupper(), I have no idea what you read :p \$\endgroup\$ – Mr. Xcoder Jul 21 '17 at 13:23
1
\$\begingroup\$

JavaScript (SpiderMonkey), 62 bytes

n=s=>(""+s.match(/([ -]|^)[A-Z]/g)).replace(/[ \-,]|null/g,"")

Try it online!

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

QuadS, 17 bytes

(?<=^| |-)[A-Z]
&

Try it online!

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

Pyth, 15 16 bytes

@rG1<R1:w"[ -]"3

Test suite

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

Pyth, 12 bytes

@rG1hMcXz\-d

Test suite here.

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

Bash (grep), 29 28 bytes

grep -oP'(?<=^| |-)[A-Z]' a

A port of my python answer but because pgrep supports variable length lookbehinds it's noticeably shorter (even accounting for the overhead of python). Stick the test cases in a file called a, output is 1 character per line.

-1 Thanks to Neil

\$\endgroup\$
  • \$\begingroup\$ ^| |- might be a shorter test? \$\endgroup\$ – Neil Jul 21 '17 at 15:43
  • \$\begingroup\$ @Neil that works here, thanks. Missed it because it doesn't work in Python \$\endgroup\$ – Chris H Jul 21 '17 at 15:58
1
\$\begingroup\$

RProgN 2, 18 bytes

`-` rû#ùr.'[a-z]'-

Explained

`-` rû#ùr.'[a-z]'-
`-`                     # Push "-" literal, and " " literal.
    r                   # replace, Replaces all "-"s with " "s.
     û                  # Split, defaultly by spaces.
      #ù                # Push the head function literally.
        r               # Replace each element of the split string by the head function, which gets each first character.
         .              # Concatenate, which collapses the stack back to a string.
          '[a-z]'-      # Push the string "[a-z]" literally, then remove it from the string underneith, giving us our output. 

Try it online!

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

PHP, 62 bytes

for(;~$c=$argn[$i++];$p=$c!="-"&$c!=" ")$c<A|$c>Z|$p?:print$c;

Run as pipe with -nR or try it online.

other solutions:

foreach(preg_split("#[ -]#",$argn)as$s)$s[0]>Z|$s<A?:print$s[0];  # 64 bytes
preg_match_all("#(?<=\s|-)[A-Z]#"," $argn",$m);echo join($m[0]);  # 64 bytes
preg_match_all("#(?<=\s|-)\p{Lu}#"," $argn",$m);echo join($m[0]); # 65 bytes
\$\endgroup\$
1
\$\begingroup\$

C++, 168 bytes

#include<string>
auto a=[](auto&s){auto r=s.substr(0,1);if(r[0]<65||r[0]>90)r="";for(int i=1;i<s.size();++i)if(s[i]>64&&s[i]<91&&(s[i-1]==32||s[i-1]==45))r+=s[i];s=r;};

Output done via the parameter

\$\endgroup\$
  • \$\begingroup\$ Would it be possible to completely remove #include<string> and assume the argument s is a std::string? \$\endgroup\$ – Zacharý Oct 5 '17 at 17:01
1
\$\begingroup\$

Lua, 79 75 bytes

for i=1,#t do for i in(" "..t[i]):gmatch"[%-| ]%u"do print(i:sub(2))end end

Try it!

I stuck a print() before the final end in the try it version because otherwise it's a mess. This program perfectly adheres to the requirements of I/O and matching, but without that extra new line it's pretty hard to read.

Input is given in the form of a table of number:string , number incrementing by 1 each time and starting at 1.

Explanation:

It for loops through a gmatch of each input string. The gmatch search is as follows:

[%-| ] - Group, search for a - or a space

%u - Search for an uppercase character

Then for each match, it prints it out minus the preceding dash or space

Edit: Golfed 4 bytes by removing the declaration of 'a' and adding the space to the input inside the for loop in, as well as changing the sub input to just 2 rather than 2,2 (which produce equivalent results)

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

Pyth, 12 bytes

Created one year after the initial answer.

rI#1hMcXQ\-d

Try it online!

Pyth, 21 bytes

Initial answer.

:+dQ"(?<=[ -])[A-Z]"1

Try it online!

\$\endgroup\$
  • \$\begingroup\$ -| is one byte less than [ -] \$\endgroup\$ – ATaco Jul 23 '17 at 23:45
  • \$\begingroup\$ @ATaco That does not seem to work \$\endgroup\$ – Mr. Xcoder Jul 24 '17 at 3:47

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.