53
\$\begingroup\$

Write a function or program that takes as its input a string and prints a truthy value if the string is a pangram (a sequence of letters containing at least one of each letter in the English alphabet) and a falsey value otherwise.

Case of letters should be ignored; If the string is abcdefghijklmnopqrstuvwXYZ, then the function should still return a truthy value. Note that the string can contain any other characters in it, so 123abcdefghijklm NOPQRSTUVWXYZ321 would return a truthy value. An empty input should return a falsey value.


Test cases

AbCdEfGhIjKlMnOpQrStUvWxYz

==> True


ACEGIKMOQSUWY
BDFHJLNPRTVXZ

==> True


public static void main(String[] args)

==> False


The quick brown fox jumped over the lazy dogs. BOING BOING BOING

==> True

This is code golf. Standard rules apply. Shortest code in bytes wins.

\$\endgroup\$
2
  • 3
    \$\begingroup\$ Plus points if your code can check if input is a Pungram. \$\endgroup\$
    – Sainan
    May 17, 2016 at 16:43
  • 14
    \$\begingroup\$ Question name request: Did the quick brown fox jump over the lazy dog? \$\endgroup\$
    – user54200
    Aug 4, 2016 at 11:59

97 Answers 97

27
\$\begingroup\$

Pyth, 7 bytes

L!-Grb0

Explanation:

L             lambda (implicit b:)
    rb0       Convert b to lowercase
   G          Lowercase alphabet, "abcd...z"
  -           Set difference, all elts of first that aren't in second
 !            Logical NOT (The empty string is falsey)

Try the full-program, single-line version here.

\$\endgroup\$
5
  • \$\begingroup\$ I think the shortest way to fix this for newlines in the input is to make a function: L!-Grb0. !-Grs.z0 would also work but is longer. \$\endgroup\$ Dec 10, 2015 at 16:13
  • \$\begingroup\$ Oh, I didn't see the question updated to include \n in the string. Thanks. \$\endgroup\$
    – lirtosiast
    Dec 10, 2015 at 22:30
  • \$\begingroup\$ 6 bytes: pyth.herokuapp.com/… \$\endgroup\$
    – Maltysen
    Dec 11, 2015 at 3:56
  • \$\begingroup\$ @Maltysen While there is a (weak) consensus on allowing strings from input to be delimited by quotes, I'm not sure about this as it goes further in requiring Python string syntax. \$\endgroup\$
    – lirtosiast
    Dec 11, 2015 at 16:04
  • \$\begingroup\$ I never would have thought an alphabet built-in would be useful... \$\endgroup\$
    – Cyoce
    Dec 12, 2015 at 8:43
18
\$\begingroup\$

Perl 6, 20 bytes

'a'..'z'⊆*.lc.comb

usage:

my &code = 'a'..'z'⊆*.lc.comb;
#  the parameter is ^ there

say code '123abcdefghijklm NOPQRSTUVWXYZ321' # True
say code '123abcdefghijklm NOPQRSTUVWXY'     # False

I used the 3 byte "french" version () of U+2286 SUBSET OF OR EQUAL TO operator instead of the 4 byte "texas" version ((<=)) which would have also required an extra space in front of it.

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

JavaScript ES6, 51 57

Edit 6 bytes save thx @user81655

a=>new Set(a.toUpperCase().match(/[A-Z]/g)).size>25

Test snippet

F=a=>new Set(a.toUpperCase().match(/[A-Z]/g)).size>25

function update() {  O.innerHTML=F(I.value) }
I.value='qwertyuiopasdfghjklzxcvbnm';update()
input { width: 70% }
<input id=I oninput='update()'>
<pre id=O></pre>

\$\endgroup\$
8
  • \$\begingroup\$ Would a.replace(/[^A-Z]|[^a-z]/g,'') or a.replace(/[^A-Z]/gi,'') work? \$\endgroup\$
    – user46167
    Dec 11, 2015 at 1:12
  • 2
    \$\begingroup\$ @ev3commander no. A and a must become the same character, else the set will keep them as distinct and the size will be > 26 \$\endgroup\$
    – edc65
    Dec 11, 2015 at 6:21
  • \$\begingroup\$ What if you use the spread operator with [...a.toUpperCase().replace(/[^A-Z]/g,'')].length>25 ? \$\endgroup\$
    – Scott
    Dec 11, 2015 at 16:55
  • \$\begingroup\$ @ScottKaye obviously no. Try it with 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' \$\endgroup\$
    – edc65
    Dec 11, 2015 at 17:35
  • 1
    \$\begingroup\$ @user81655 right, it works, great. Thanks. I should not answer comments while asleep \$\endgroup\$
    – edc65
    Dec 12, 2015 at 11:07
12
\$\begingroup\$

GS2, 11 9 bytes

☺ 6ΘàB1."

Thanks to @MitchSchwartz for golfing off 2 bytes!

The source code uses the CP437 encoding. Try it online!

How it works

☺              Push 32 (code point of space).
  6            Bitwise OR.
   Θ           Make a block of these two instructions and map it over the input.
               This turns uppercase letters into their lowercase counterparts.
      à        Push the lowercase alphabet.
       B1      Swap and apply set difference.
         ."    Push the logical NOT of the length of the result.
\$\endgroup\$
2
  • \$\begingroup\$ quick block m2 (\xe9) saves 2 bytes. \$\endgroup\$ Dec 10, 2015 at 5:24
  • \$\begingroup\$ @MitchSchwartz Oh, so that's how you use those. Thanks! \$\endgroup\$
    – Dennis
    Dec 10, 2015 at 5:29
11
\$\begingroup\$

R 50 ,46 39 bytes

all(sapply(letters,grepl,readline(),T))

Edit drops the need for tolower by adding ignore.case=TRUE (T)

\$\endgroup\$
2
  • \$\begingroup\$ Not too familiar with R, but shouldn't ignore.case=TRUE (T) be included in the count as well then? \$\endgroup\$
    – Ruslan
    Dec 11, 2015 at 13:30
  • 2
    \$\begingroup\$ @Ruslan It is! It is the Tas the end, thanks to argument placement matching there is no need to actually specify the name of the argument (and T is the default alias for TRUE). The code written here performs the needed action as is, without any need to add anything. \$\endgroup\$
    – plannapus
    Dec 11, 2015 at 14:29
9
\$\begingroup\$

Python 2, 53 51 bytes

f=lambda s,c=65:c>90or(chr(c)in s.upper())*f(s,c+1)

Alternate solutions:

lambda s:all(chr(c)in s.upper()for c in range(65,91))

lambda s:not set(range(65,91))-set(map(ord,s.upper()))

Thanks to xnor for pointing out that sets have an <= operator, for an alternate 51:

lambda s:set(range(65,91))<=set(map(ord,s.upper()))
\$\endgroup\$
5
  • 1
    \$\begingroup\$ If I'm not mistaken, the last expression is the same as lambda s:set(range(65,91))<=set(map(ord,s.upper())), also for 51. \$\endgroup\$
    – xnor
    Dec 10, 2015 at 5:06
  • \$\begingroup\$ Python 3.5 can save bytes here: p=lambda s:{*range(65,91)}<={*map(ord,s.upper())}. By the way, I can't seem to find any rules on whether a lambda needs to be assigned (as in your first case) or not (as in your later ones). Help? \$\endgroup\$ Dec 11, 2015 at 16:30
  • \$\begingroup\$ @TimPederick Naming the lambda is unnecessary unless you need to use the function elsewhere, like in the first recursive solution. \$\endgroup\$ Dec 11, 2015 at 16:57
  • \$\begingroup\$ @TimPederick Thanks for pointing that out. I renamed my answer as Python 2 instead of just Python. You have my blessing to post that as a new answer if you want, which I think would be ok by community norms although I'm not sure. \$\endgroup\$ Dec 11, 2015 at 17:33
  • \$\begingroup\$ @FryAmTheEggman: Thanks for clarifying. That distinction hadn't occurred to me! I've also found a meta post explaining the rule. There goes two bytes from a few things I've written... \$\endgroup\$ Dec 12, 2015 at 13:51
8
\$\begingroup\$

O, 11 bytes

GQ_s{n-}dS=

Try it online.

Sadly, O does not have set difference :/

Explanation

G            Pushes the alphabet to the stack
 Q           Pushes input to the stack
  _          Converts the string to lowercase
   s         Split string into char array
    {  }d    Iterate through array
     n       Pushes current element to the stack
      -      String subtraction
         S   Pushes a blank string to the stack
          =  Equals
\$\endgroup\$
8
\$\begingroup\$

All of these regexes use their engines' respective case insensitivity flags, so that has not been counted towards the byte counts. Even though some use \pL (a shorthand for \p{L}) instead of [A-Z], they still need the flag, due to comparing characters via backreference. Without it, they would need to apply the flag inline, (?i) inserted at the beginning, costing 4 extra bytes.

Regex (Perl 5 / PCRE / Boost / Pythonregex), 21🐌, 22🐌, 24, or 25 bytes

Quite simply, this regex works by asserting that there are at least 26 alphabetical characters in the string that do not match with any character to the right of themselves. Each of these characters will be the last occurrence of a given letter of the alphabet in the string; as such, they are all guaranteed to be different letters, and asserting that there are 26 of them implies that the full set A-Z is covered.

(.*(\pL)(?!.*\2)){26} (21 bytes) 🐌 - Try it online! (Perl 5)

Using \pL instead of [A-Z] to match alphabetical characters imposes the requirement that the input must be in ASCII, because \pL matches all Unicode alphabetical characters (including those that are extended ASCII in common codepages); so an accented letter, for example, would count towards consuming the target of 26 loop iterations. Some other regex engines only support this syntax in the form of \p{L} (which offers no advantage over [A-Z] for this particular problem, being equal in length) and not with the shortened syntax of \pL.

This bare-bones version of the regex is extremely slow, due to an excessively huge amount of backtracking both for pangrams and non-pangrams, but will always give the correct result when given enough time. Its search for the 26 matches proceeds in the most pessimal way possible.

Using a lazy quantifier speeds it up greatly when matching pangrams, but it's still incredibly slow to yield non-matches when given non-pangrams:

(.*?(\pL)(?!.*\2)){26} (22 bytes) 🐌

Try it online! (Perl 5)
Try it online! (PCRE2 / C++, with backtrack limit adjusted)
Try it online! (PCRE2 / PHP, with backtrack limit adjusted)

Changing the main loop to an atomic group allows the regex to also yield non-matches at a reasonable speed:

(?>.*?(\pL)(?!.*\1)){26} (24 bytes)

Try it on regex101 (PCRE1)
Try it online! (Python import regex)

Adding an anchor is not necessary to make the regex yield correct results, but speeds up non-matches further, by preventing the regex engine from continuing to try for a match at every character of the string (because if it fails to match at the beginning, we know it's guaranteed not to match anywhere in the same string, but the regex engine can't know that):

^(?>.*?(\pL)(?!.*\1)){26} (25 bytes)

Try it on regex101 (PCRE1)
Try it online! (Python import regex)
Try it online! (Perl 5)
Try it online! (PCRE2 / C++)
Try it online! (PCRE2 / PHP)
Try it online! (Boost / C++)

Regex (.NET / Java / Ruby), 23🐌, 24🐌, 26, or 27 bytes

These regex engines don't support \pL (they support \p{L}, but that isn't useful when we already need the case insensitivity flag anyway), thus [A-Z] is used:

(.*([A-Z])(?!.*\2)){26} (23 bytes) 🐌
(.*?([A-Z])(?!.*\2)){26} (24 bytes) 🐌
(?>.*?([A-Z])(?!.*\1)){26} (26 bytes)
^(?>.*?([A-Z])(?!.*\1)){26} (27 bytes)

^            # 1. Anchor to the start of the string (without this, the regex would still
             #    work but would be slower in its non-matches, due to trying to match at
             #    every character position in the string, which we know will fail, but
             #    the regex engine can't know)
(?>          # 2. Start an atomic group (every complete iteration of matching this group
             #    is set in stone, and will not be backtracked); without only a normal
             #    group, the regex would still work, but with most non-pangram inputs,
             #    would take longer than the age of the universe to yield a non-match,
             #    due to trying every way of matching ".*?" at every iteration of the loop
    .*?      # 3. Skip zero or more characters, as few as possible in order to make the
             #    following match
    ([A-Z])  # 4. Capture and consume an alphabetical character in \1
    (?!      # 5. Negative lookahead: Match outside (with zero-width) only if the inside
             #    does not match
        .*   # 6. Skip forward by zero characters or more in an attempt to make the
             #    following expresison match
        \1   # 7. Match the character captured in \1
    )        # 8. The effect of this negative lookahead is to assert that at no point
             #    right of where \1 was captured does any character match \1
){26}        # 9. Only match if this group can be matched exactly 26 times in a row,
             #    i.e. if we can find 26 characters in the range A-Z that don't match
             #    any character right of themselves, i.e. that we can find the last
             #    occurrence of 26 different alphabetical character in the string.

Try it online! (.NET / C#)
Try it online! (Java)
Try it online! (Ruby)

Regex (ECMAScript / Python), 23🐌, 24🐌, 32, or 33 bytes

The same progression of speed applies:

(.*([A-Z])(?!.*\2)){26} (23 bytes) 🐌 - Try it online! (ECMAScript) / (Python)
(.*?([A-Z])(?!.*\2)){26} (24 bytes) 🐌 - Try it online! (ECMAScript) / (Python)

ECMAScript and Python lack atomic groups, so they must be emulated using lookahead+capture+backref:

((?=(.*?([A-Z])(?!.*\3)))\2){26} (32 bytes) - Try it online! (ECMAScript) / (Python)
^((?=(.*?([A-Z])(?!.*\3)))\2){26} (33 bytes) - Try it online! (ECMAScript) / (Python)


Edit: Silly me, I assumed that this problem required variable-length lookbehind or other tricks that substitute for it, without even trying to do it without that. Thanks to @Neil for pointing this out.

\$\endgroup\$
7
  • \$\begingroup\$ You can save a byte by using positive lookahead instead of negative. This matches the last of each letter rather than the first, but the overall result is the same, excecpt of course that it works in less powerful regex engines such as ES6. \$\endgroup\$
    – Neil
    Dec 29, 2019 at 11:25
  • \$\begingroup\$ Try it online! \$\endgroup\$
    – Neil
    Dec 29, 2019 at 11:25
  • \$\begingroup\$ @Neil Oops! How embarrassing. Thanks for letting me know. (A shame, since I thought this problem was even better than Do you make me up? for illustrating the differences between engines.) I guess I'm guilty here of "When you have a hammer, every problem looks like a nail." I'll try to avoid that pitfall in the future. \$\endgroup\$
    – Deadcode
    Dec 30, 2019 at 3:33
  • \$\begingroup\$ Downvoting this because these (at least the Perl ones) are snippets, not programs or functions. They are just the regex pattern that needs to be incorporated into a program. \$\endgroup\$
    – Xcali
    Jan 19, 2021 at 16:38
  • 1
    \$\begingroup\$ @Xcali They are full programs with Regex as the language. I never claim anywhere in this answer that they are programs in Perl, Ruby, Java, etc. They are programs in various flavors of Regex, with the regex engine of Perl, for example, being the language in use, not Perl itself. \$\endgroup\$
    – Deadcode
    Jan 19, 2021 at 17:49
6
\$\begingroup\$

Julia, 38 bytes

s->endof(∩('a':'z',lowercase(s)))>25

This is simple - lowercase deals with the uppercase/lowercase issue, 'a':'z' holds all of the lowercase letters, is intersection, removes any character that isn't a letter and, because 'a':'z' comes first, will only have one of each letter that appears in s. endof is the shortest way to get the length of the resulting array, and if it's 26, then it's a pangram (it can't be more than 26, and >25 saves a byte relative to ==26).

\$\endgroup\$
6
\$\begingroup\$

Ruby, 41 33

->s{(?a..?z).all?{|c|s[/#{c}/i]}}

Usage

p=->s{(?a..?z).all?{|c|s[/#{c}/i]}}
p["AbCdEfGhIjKlMnOpQrStUvWxYz"] 
  #=> true
p["ACEGIKMOQSUWY
BDFHJLNPRTVXZ"]
  #=> true
p["public static void main(String[] args)"]
  #=> false
p["The quick brown fox jumped over the lazy dogs. BOING BOING BOING"]
  #=> true

Thanks to Vasu Adari for saving me 8 bytes

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

05AB1E, 4 bytes

lêAå

Try it online!

l    # Push lowercase input.
 ê   # Push sorted, uniquified lowercase input.
  A  # Push lowercase alphabet.
   å # Is lowercase alphabet in sorted, uniquified, lowercase input?
     # True if panagram, false if not.
\$\endgroup\$
5
\$\begingroup\$

Retina, 22 bytes

Msi`([a-z])(?!.*\1)
26

Try it online.

The first line matches any letter which does not appear again later in the string. That ensures that we don't match each letter at most once, no matter how often it occurs. Match mode will by default replace the string with the number of matches found. So in the second stage, we match 26 against the result of the first input, which will give either 0 or 1, depending on whether we found the maximum of 26 matches or not.

\$\endgroup\$
5
\$\begingroup\$

Python 3.5, 47 bytes

lambda s:{*map(chr,range(65,91))}<={*s.upper()}

Same principle as Mitch Schwartz's answer, but using the PEP 0448 enhancements to * unpacking, first introduced in Python 3.5.

This version differs slightly from what I wrote in my comment to Mitch's post, in that I turn the numbers into letters rather than vice versa. That's because that's how I wrote my original attempts at a solution, before discovering that I couldn't out-golf Mitch without outright copying his approach. So consider that tweak my one remaining shred of originality!

\$\endgroup\$
5
\$\begingroup\$

Haskell, 59 56 53 51 bytes

p s=and[any(`elem`map toEnum[a,a+32])s|a<-[65..90]]

Try it online!

Explanation:

Give an input string s, for each a in range 65 to 90 (the ASCII codes for A to Z) it is checked whether any character in s is equal to either a (the upper case character) or a+32 (the lower case character), converted to a character by toEnum. This generates a list of booleans. and checks if they're all True.

Old version:

import Data.Char
p s=and[any((==)a.toUpper)s|a<-['A'..'Z']]

For every upper case alphabet letter, check whether some letter from s in upper case is equal to it. any(==a)s is the same as elem a s but allows to modify the elements of s before the comparison - in this case, covert them to upper case.

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

Haskell, 43 bytes

f s=until(all(`notElem`s))(succ<$>)"Aa">"["

Try it online!

Iterates through the lowercase/uppercase pairs until it finds one where both are not elements of the input, and checks that this failure is past the alphabet.

\$\endgroup\$
5
\$\begingroup\$

Vim, 30 26 bytes

:%s/\A*/\r/g
:sor ui
26Dr1

Try it online!

Let's get this language of the month started! I am still a beginner in Vim, so golfing suggestions are much appreciated :)

Explanation

The first line of the program uses a regex to substitute any (possibly empty) sequence of non-alphabetic characters (\A*) with a newline; since the empty string also gets matched, this will result in a series of lines each containing at most one character, which will be a letter. The first line will always be empty (the initial empty string became a newline).

:sor ui sorts the lines ignoring case, and removes duplicates (also ignoring case). If the input was a pangram we will now have an empty line followed by 26 lines each with a character from a to z; if the input was not a pangram, some of those lines will be missing.

26D deletes the first 26 lines, which will leave us with either z (for a pangram) or an empty string (for a non-pangram). The only truthy values in Vim are non-zero numbers (or strings starting with a non-zero number), so our last step will be r1 (replace the first character with 1) which will result in 1 for a pangram, and an empty string otherwise.

\$\endgroup\$
5
\$\begingroup\$

These have the same regex as in my regex answer. I felt it was worth posting a standalone answer showing its use in languages that don't require an import to access regex functions (resulting in very effective golf). In order of how favorably it compares against the current best non-regex answer.

This answer previously showed programs/functions that couldn't handle multiline input (as the challenge demonstrates is required by its second test case), but they all do so properly now unless otherwise noted.

Java, 46 bytes

a->a.matches("(?si:.*([A-Z])(?!.*\\1)){26}.*") (46 bytes, always slow) - Try it online!
a->a.matches("(?si:.*?([A-Z])(?!.*\\1)){26}.*") (47 bytes, slow for non-matches) - Try it online!
a->a.matches("(?si)(?>.*?([A-Z])(?!.*\\1)){26}.*") (50 bytes, reasonable speed) - Try it online!

PHP, 53 or 55 bytes

PHP imposes a strict backtracking limit (or time limit?) on its regexes, so the version that would be 52 bytes doesn't work at all; it always returns an empty result (except for very short non-pangram strings, for which it prints 0).

<?=preg_match('/(.*?(\pL)(?!.*\2)){26}/si',$argv[1]); (53 bytes) - Try it online!

The 53 byte version, however, actually runs fast; it prints an empty result or 0 for false, and prints 1 for true. However, with sufficiently long pangram strings having a long separation between occurrences of new letters, it returns a false negative, due to taking too long to process the string.

<?=preg_match('/(?>.*?(\pL)(?!.*\1)){26}/si',$argv[1]); (55 bytes) - Try it online!
<?=preg_match('/^(?>.*?(\pL)(?!.*\1)){26}/si',$argv[1]); (56 bytes) - Try it online!

These versions print 0 for false and 1 for true.

This beats 640KB's answer when it is ported to handle multiline input:

<?=!array_diff(range(a,z),str_split(strtolower($argv[1]))); (59 bytes) - Try it online!

JavaScript ES9, 38 bytes

a=>/(.*([A-Z])(?!.*\2)){26}/si.test(a) (38 bytes, always slow) - Try it online!
a=>/(.*?([A-Z])(?!.*\2)){26}/si.test(a) (39 bytes, slow for non-matches) - Try it online!
a=>/((?=(.*?([A-Z])(?!.*\3)))\2){26}/si.test(a) (47 bytes, fairly reasonable speed) - Try it online!
a=>/^((?=(.*?([A-Z])(?!.*\3)))\2){26}/si.test(a) (48 bytes, very reasonable speed) - Try it online!

When looping this set of test cases, it can be seen that the 48 byte version is about 12 times as fast as the 47 byte version (in SpiderMonkey's regex engine).

This now ties in length with l4m2's answer, which counts individual regex matches. Given the speed difference, that answer obviously wins.

Ruby, 35 bytes

->s{s=~/(.*([A-Z])(?!.*\2)){26}/mi} (35 bytes, always slow) - Try it online!
->s{s=~/(.*?([A-Z])(?!.*\2)){26}/mi} (36 bytes, slow for non-matches) - Try it online!
->s{s=~/(?>.*?([A-Z])(?!.*\1)){26}/mi} (38 bytes, fairly reasonable speed) - Try it online!
->s{s=~/^(?>.*?([A-Z])(?!.*\1)){26}/mi} (39 bytes, very reasonable speed) - Try it online!

When looping this set of test cases, the same result is seen: the 39 byte version is 12 times as fast as the 38 byte version.

This is 2 bytes longer than Alexis Andersen's mixed code/regex answer.

Ruby -n0, 30 bytes

Prints nil for false and 0 for true, which are respectively falsey and truthy in Ruby. If printing 0 or 1 is desired, replace ~ with !! (+1 byte).

p ~/(.*([A-Z])(?!.*\2)){26}/mi (30 bytes, always slow) - Try it online!
p ~/(.*?([A-Z])(?!.*\2)){26}/mi (31 bytes, slow for non-matches) - Try it online!
p ~/(?>.*?([A-Z])(?!.*\1)){26}/mi (33 bytes, fairly reasonable speed) - Try it online!
p ~/^(?>.*?([A-Z])(?!.*\1)){26}/mi (34 bytes, very reasonable speed) - Try it online!

This is 2 bytes longer than Alexis Andersen's answer when it is ported to be a full program using -n0 instead of a lambda (and it prints false or true):

p (?a..?z).all?{|c|~/#{c}/i} (28 bytes) - Try it online!

Perl 5 -p0, 28 bytes

$_=/(.*(\pL)(?!.*\2)){26}/si (28 bytes, always slow) - Try it online!
$_=/(.*?(\pL)(?!.*\2)){26}/si (29 bytes, slow for non-matches) - Try it online!
$_=/(?>.*?(\pL)(?!.*\1)){26}/si (31 bytes, fairly reasonable speed) - Try it online!
$_=/^(?>.*?(\pL)(?!.*\1)){26}/si (32 bytes, very reasonable speed) - Try it online!

This is 2 bytes longer than Xcali's regex + hash answer when its [a-z] is replaced with \pL. Also, for some reason that answer only requires the -p command-line parameter yet still works with multiline input, while this one requires -p0 to do so.

Perl 5, 40 bytes

say@ARGV[0]=~/(.*(\pL)(?!.*\2)){26}/si+0 (40 bytes, always slow) - Try it online!
say@ARGV[0]=~/(.*?(\pL)(?!.*\2)){26}/si+0 (41 bytes, slow for non-matches) - Try it online!
say@ARGV[0]=~/(?>.*?(\pL)(?!.*\1)){26}/si+0 (43 bytes, fairly reasonable speed) - Try it online!
say@ARGV[0]=~/^(?>.*?(\pL)(?!.*\1)){26}/si+0 (44 bytes, very reasonable speed) - Try it online!

This is 4 bytes longer than a port of Xcali's regex + hash answer with [a-z] replaced with \pL:

++@a{(uc@ARGV[0])=~/\pL/g};say%a==26 (36 bytes) - Try it online!

Reading multiline input from stdin instead of a command-line argument would be 4 bytes longer, replacing @ARGV[0] with join('',<>).

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

CJam, 11 bytes

'[,65>qeu-!

This is a complete program. Try it online.

Explanation:

'[,65>  Build upper case alphabet (see CJam tips thread).
q       Get input.
eu      Convert to all upper case.
-       Set difference between alphabet and upper cased input.
!       Negate.
\$\endgroup\$
4
\$\begingroup\$

Minkolang 0.14, 18 bytes

$o7$ZsrlZ'26'$ZN.

Try it here.

Explanation

$o                    Read in whole input as characters
  7$Z                 Uppercase every letter
     s                Sort
      r               Reverse
       lZ             Alphabet - uppercase and lowercase
         '26'         Pushes 26 on the stack
             0$Z      Count how often the top 26 numbers of the stack appear in the stack
                N.    Output as number and stop.
\$\endgroup\$
4
\$\begingroup\$

PowerShell v3+, 65 56 52 Bytes

($args.ToLower()-split''|sls [a-z]|group).Count-eq26

Thanks to TessellatingHeckler for the 9-byte golf.

  • Takes the input string, converts it .ToLower()case, then -splits on every character
  • Those are fed into an alias sls for Select-String which matches based on a regex [a-z] to pull out only the letters
  • Those are then fed into Group-Object, so we're only selecting one individual instance of each letter
  • That is then .Counted to see if it's -equal to 26, and prints True or False accordingly
  • Requires PowerShell v3 or newer for the sls alias
\$\endgroup\$
2
  • \$\begingroup\$ It's a lot easier to pinch someone else's effort and try and shorten it a bit, than to read the questions from scratch - and more fun to compete within PowerShell than to go directly up against CJam and friends. But I can stop chasing your answers if it's annoying, sorry. \$\endgroup\$ Dec 15, 2015 at 16:58
  • \$\begingroup\$ @TessellatingHeckler Not annoying! :D I'm just trying to give you more encouragement! \$\endgroup\$ Dec 15, 2015 at 18:00
4
\$\begingroup\$

R, 53 45 bytes

all(97:122%in%utf8ToInt(tolower(readline())))

Old version at 53 bytes:

all(letters%in%strsplit(tolower(readline()),"")[[1]])

Usage:

> all(97:122%in%utf8ToInt(tolower(readline())))
The quick brown fox jumps over the lazy dog
[1] TRUE
> all(97:122%in%utf8ToInt(tolower(readline())))
Write a function or program that takes as its input a string and prints a truthy value if the string is a pangram and a falsey value otherwise.
[1] FALSE
> all(97:122%in%utf8ToInt(tolower(readline())))
123abcdefghijklm NOPQRSTUVWXYZ321
[1] TRUE
> all(97:122%in%utf8ToInt(tolower(readline())))
Portez ce vieux whisky au juge blond qui fume
[1] TRUE
\$\endgroup\$
4
\$\begingroup\$

2sable, 6 5 bytes

6 byte version:

AIl-g_

Try it online!

Explanation:

A        Push alphabet
 Il      Push lowercase input
   -     Remove all chars of input from alphabet
    g    Get length of the remainder
     _   Print negative bool, where length < 1 = 1 (true), length > 0 = 0 (false)

5 byte version, inspired by carusocomputing's 05AB1E answer:

lÙ{Aå

Try it online!

Explanation:

l        Push lowercase input
 Ù{      Push sorted uniquified input
   A     Push alphabet
    å    Is alphabet in sorted, uniquified input?
\$\endgroup\$
4
\$\begingroup\$

J, 23 bytes

(u:65+i.26)*/@e.toupper

Try it online!

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

MATLAB / Octave, 35 33 bytes

@(x)~nnz(setdiff(65:90,upper(x)))

Try it online!


The anonymous function returns a logical 1 if the input x is a pangram, or a logical 0 if it isn't.

Essentially it uses the same approach as @ThomasKwa's Pyth solution. The set difference between all characters in the upper case alphabet range (65:91) and the input string (converted to upper case). Any characters that are in the alphabet but not in the input string are returned by setdiff. Only if the array returned by the set difference is empty is the string a pangram.

Using upper case instead of lower case saves a couple of bytes compared with 'a':'z' because the ASCII value can be used instead to make the range.

\$\endgroup\$
1
  • \$\begingroup\$ Great answer! Mine was 10 bytes longer \$\endgroup\$
    – Luis Mendo
    Dec 10, 2015 at 23:37
4
\$\begingroup\$

Brachylog, 4 bytes

ḷo⊇Ạ

Try it online!

        The input
ḷ       lowercased
 o      sorted
  ⊇     is a superlist of
   Ạ    the lowercase alphabet.
\$\endgroup\$
4
\$\begingroup\$

Julia, 26 25 bytes

!s='a':'z'⊆lowercase(s)
  • remove . by @MarcMush

Attempt This Online!

\$\endgroup\$
1
  • \$\begingroup\$ you can remove the dot for -1 byte \$\endgroup\$
    – MarcMush
    Jul 5, 2022 at 21:20
4
\$\begingroup\$

K (ngn/k), 36 19 17 bytes

{~#(97+!26)^0+_x}

Try it online!

-2 bytes thanks to ngn!

Return 1 for true, 0 for false.

Explanation:

{~#(97+!26)^0+_x}      / Main program. x is input
              _        / Lowercase
            0+         / Convert each character to ASCII value
           ^           / Without (set function)
   (97+!26)            / Lowercase alphabet (ASCII value)
  #                    / Length
 ~                     / Not
\$\endgroup\$
7
  • \$\begingroup\$ What do you mean by "Doesn't work with strings that contains characters other than the alphabet"? Your test harness shows it working with such strings. \$\endgroup\$
    – Deadcode
    Jul 18, 2022 at 0:36
  • \$\begingroup\$ @Deadcode I mean strings that are valid pangrams but contain other characters, like 123abcdefghijklmnopqrstuvwxyz. My fault, will correct it in the post. \$\endgroup\$
    – oeuf
    Jul 18, 2022 at 7:53
  • \$\begingroup\$ But what does it do wrong? I tried your example of 123abcdefghijklmnopqrstuvwxyz and it correctly identifies it as a pangram. If I remove any letter, it correctly identifies it as not a pangram. \$\endgroup\$
    – Deadcode
    Jul 18, 2022 at 8:05
  • \$\begingroup\$ @Deadcode I just realized that it works for some reason, which I didn't expect it to work. Either way, thanks for helping me! Will edit the post. \$\endgroup\$
    – oeuf
    Jul 18, 2022 at 13:24
  • \$\begingroup\$ ""~ -> ~# \$\endgroup\$
    – ngn
    Jul 18, 2022 at 20:24
4
+400
\$\begingroup\$

Prolog (SWI), 57 bytes

\O:- \+ (between(97,122,Z),\+sub_atom_icasechk(O,_,[Z])).

Try it online!

Buried deep within the Prolog library is the very convenient predicate sub_atom_icasechk, which is a "half case-insensitive" check for a substring (half as in lowercase characters can match uppercase but not vice-versa). We just need to surround this in a check that all lowercase letters succeed this check.

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

Japt, 14 bytes

#ao#{ e@Uv fXd

Try it online!

How it works

        // Implicit: U = input string
#ao#{   // Generate a range of integers from charCode("a") to charCode("{").
e@      // Check if every item X in this range returns truthily to:
Uv fXd  //  convert U to lowercase, and put all instances of X.toCharCode() in an array.
        // This returns false if U does not contain one of the characters.
        // Implicit: output last expression
\$\endgroup\$
3
\$\begingroup\$

Bash, 45 42 bytes

41 byte program, plus 1 because it must be invoked with bash -e:

for i in {a..z}
{ [ ${1//[^$i${i^}]} ]
}

Amazingly, I managed a Bash answer with no quote characters! (yes, I checked with inputs beginning with -f and the like).

This assumes a locale where the lower-case English letters are contiguous from a to z. Input is via the first argument to the program.

The way this works is, for each alphabetic letter $i, we test whether the string contains $i or its upper-case equivalent ${i^} by removing all other characters. If this results in the empty string, then the input did not contain that letter, and we exit with 1 (false). If we have a non-empty result, then we passed the test and move on to the next letter. If the input string contains every English letter, we will reach the end of the program, thus exiting with 0 (true).

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Very nice. Less golfy but kinda fun alternative: comm -23 <(printf %s\\n {A..Z}) <(sort <(printf %s\\n ${1^^})) has no output iff true. Try it online! \$\endgroup\$
    – Jonah
    Mar 29, 2021 at 2:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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