46
\$\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 '16 at 16:43
  • 8
    \$\begingroup\$ Question name request: Did the quick brown fox jump over the lazy dog? \$\endgroup\$ – user54200 Aug 4 '16 at 11:59

84 Answers 84

3
\$\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 33 bytes

->s{~/(.*([A-Z])(?!.*\2)){26}/mi} (33 bytes) - Try it online!
->s{~/(.*?([A-Z])(?!.*\2)){26}/mi} (34 bytes) - Try it online!
->s{~/(?>.*?([A-Z])(?!.*\1)){26}/mi} (36 bytes) - Try it online!
->s{~/^(?>.*?([A-Z])(?!.*\1)){26}/mi} (37 bytes) - Try it online!

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

This ties with Alexis Andersen's mixed code/regex answer. Given the speed difference, that answer obviously wins.

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\$
1
  • \$\begingroup\$ @l4m2 That's the shortest/slowest version, so it does a LOT of backtracking before making its final match on abcdefghijklmnopqrstuvwxybz. Which will be to count a_cdefghijklmnopqrstuvwxybz as the last occurrence of each letter matched in the ([A-Z]) - yes, it will skip over the first b, which happens inside the .* that comes before ([A-Z]). \$\endgroup\$ – Deadcode Apr 2 at 4:41
2
\$\begingroup\$

TeaScript, 12 bytes

Sz.e»xL.I(l©

First TeaScript post since I killed TeaScript :p

Try it online

Ungolfed

Sz.e(#xL.I(l))

Sz   // Lower case alphabet
.e(#   // Loop through alphabet, ensure
       // for every character, below returns true
    xL    // Input lowercased
    .I(l) // Checks if above contains current char
)
\$\endgroup\$
1
  • 1
    \$\begingroup\$ ;-; I feel bad now. TBH I like TeaScript the most. \$\endgroup\$ – Conor O'Brien Dec 10 '15 at 19:24
2
\$\begingroup\$

JavaScript ES6, 124 114 113 bytes

I'm sure this can be golfed more.

v=(Q,s=[...Array(26)].map((x,i)=>String.fromCharCode(i+97)))=>s.length-1?Q.search(RegExp(s.pop(),"i"))+1&&v(Q,s):1

Generates an anonymous function.

v=(Q,s=[...Array(26)].map((x,i)=>String.fromCharCode(i+97)))=>s.length-1?Q.search(RegExp(s.pop(),"i"))+1&&v(Q,s):1

alert(v(prompt("Enter pangram:")));

\$\endgroup\$
2
  • \$\begingroup\$ @apsillers I think I found the problem. Please test it again (my browser does not support ES6 atm) \$\endgroup\$ – Conor O'Brien Dec 10 '15 at 19:21
  • \$\begingroup\$ Yep, looks good now! \$\endgroup\$ – apsillers Dec 10 '15 at 19:30
2
\$\begingroup\$

C, 107 bytes

#include<string.h>
int p(char*i){int a=64;while(++a<91)if(!strchr(i,a)&!strchr(i,a+32))return 0;return 1;}
\$\endgroup\$
2
\$\begingroup\$

ES6, 68 bytes

s=>[..."abcdefghijklmnopqrstuvwxyz"].every(x=>RegExp(x,"i").test(s))

That string looks awfully wasteful, but I don't know any better way.

\$\endgroup\$
2
  • \$\begingroup\$ Maybe using a range of charcodes? \$\endgroup\$ – Cyoce Dec 12 '15 at 8:51
  • \$\begingroup\$ @Cyoce That got me thinking and I tried a range of base 36 digits but so far it still takes 70 bytes: s=>[...Array(x=9,26)].every(z=>RegExp((++x).toString(36),"i").test(s)) \$\endgroup\$ – Neil Dec 13 '15 at 0:29
2
\$\begingroup\$

Scala, 59 48 46 bytes

print(('a'to'z'diff(readLine.map(_|32)))==Nil)
\$\endgroup\$
1
  • \$\begingroup\$ Using 32| rather than _|32 will (yield a warning but) shave off one more byte \$\endgroup\$ – Jacob May 17 '16 at 14:48
2
\$\begingroup\$

C#, 91 bytes

Requires (18 bytes):

using System.Linq;

Actual function (73 bytes):

bool P(string s)=>s.ToUpper().Distinct().Where(x=>x>64&&x<91).Count()>25;

How it works: the function first converts everything to uppercase, then removes all duplicates and only keeps the letters. If count of items in the resulting enumerable exceeds 25 (then it must be 26), it's a pangram.

\$\endgroup\$
2
  • \$\begingroup\$ && can be golfed to &, and bool p(string s)=> can be golfed to s=> \$\endgroup\$ – Kevin Cruijssen Feb 22 '18 at 14:28
  • \$\begingroup\$ You can save 8 bytes by removing redundant Where method and moving condition to Count method. \$\endgroup\$ – Jirka Picek Jan 24 '20 at 8:50
2
\$\begingroup\$

PlatyPar, 14 bytes

'a'z_,X,F(x;l!

Explanation (stack visualizer feature coming soon!):

               ## Implicit: push the input (as a string) to the stack
'a'z_          ## Push the range of a-z (the alphabet) to the stack
     ,X        ## Invert stack, expand input string into individual characters
       ,       ## Invert again
        F  ;   ## Fold (While stack.length > 1)
         (      ## Rotate left, moving the first letter of the input string to the top
          x     ## remove any occurences of that letter from the alphabet array
            l! ## Negate the length of the array, so if there's nothing left
               ## output true, else output false

If I had a ridiculous "push all letters of the alphabet" function this would be 10...

Try it online!

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

Pyke, 6 bytes

l1GR-!

Try it here!

l1     -   input().lower()
  G -  -  set_difference(alphabet,^)
     ! - not ^
\$\endgroup\$
2
\$\begingroup\$

Batch, 126 + 2 = 128 bytes

@set p="%*"
@for %%a in (a b c d e f g h i j k l m n o p q r s t u v w x y z)do @set q=!p:%%a=!&if !q!==!p! exit/b 1
@exit/b

Requires CMD /V /C <filename> <input string> so I added 2 bytes for the /V. Alternative 87 + 2 + 26 = 115 byte version:

@set p="%*"
@for %%a in (?)do set q=!p:%%a=!&if !q!==%p% exit/b 1
@exit/b

(+26 for the files named a, b, c ... z that need to exist in the current directory.)

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

Rust, 64 bytes

|s:&str|(65u8..91).all(|c|s.to_uppercase().contains(c as char))

You can take a range over chars in Rust,

'a'..'{'

but it's presently useless since you can't iterate over it or collect it or do anything with it. They say arithmetic with characters doesn't make sense, so they won't implement the Add and One traits for it.

Still, lambdas and iterators and type inference keeps it reasonably small.

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

MathGolf, 11 7 bytes

!▀_▄+▀=

Try it online!

Explanation

MathGolf just got a lowercase operator!, ! is the factorial operator for ints, floats and lists, but now it also works as a lowercase operator for strings.

!          convert input to lowercase
 ▀         get unique characters as string
  _        duplicate
   ▄+      add the lowercase alphabet to the second copy
     ▀=    get unique elements and check that they are unchanged
\$\endgroup\$
2
\$\begingroup\$

Kotlin, 47 bytes

{s:String->('a'..'z').all{s.contains(it,true)}}

Try it online!

\$\endgroup\$
3
  • \$\begingroup\$ It seems that both this answer and the other one operate on an existing variable, when the challenge requires that a function be built. \$\endgroup\$ – Wheat Wizard Jan 23 '20 at 14:09
  • \$\begingroup\$ @PostRockGarfHunter Thanks for letting me know. I've updated the answer by adding a Try it online! link so that the solution can be tested. I hope it's OK like this, as I've seen this approach used by others. \$\endgroup\$ – adrian.nastase Jan 23 '20 at 20:28
  • 1
    \$\begingroup\$ @JoKing Thanks, I'll keep that in mind! I've updated my answer. I hope it's OK now. \$\endgroup\$ – adrian.nastase Jan 27 '20 at 5:19
2
\$\begingroup\$

Husk, 9 bytes

¦m_⁰…'a'z

Try it online!

Explanation

¦m_⁰…'a'z
    …'a'z inclusive range from a to z
 m_⁰      convert input to lowercase
¦         are all alphabets present in it?
\$\endgroup\$
0
2
\$\begingroup\$

Perl 5 -MList::Util=uniq -p0, 22 bytes

$_=26==uniq uc=~/\pL/g

Try it online!

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

Jelly, 7 6 bytes

ŒlØaḟṆ

Try it online!

Unless I'm missing something, this is the first jelly answer here.

-1 thanks to the Jelly gurus (caird/chartz and unrelatedstring) in the JHT chat room. Y'all are poggers.

Explained (old)

ŒlQṢØaẇ → a monadic link. Takes a single string as input. We will call that string "S". The flow value of the chain starts as S.
Œl      → The lower case atom. The flow value of the chain is now S.lowercase()
  Q     → The uniquify atom. The flow value of the chain is now unique_elements(S.lowercase())
   Ṣ    → The sort atom. The flow value is now sorted(unique_elements(S.lowercase()))
    Øaẇ → A nilad-dyad pair of the lower case alphabet atom and the is sublist atom. ẇ requires the needle to search for to be on the left and the haystack to search to be on the right. The flow value is now "abcd...xyz" in sorted(unique_elements(S.lowercase())). This consequently has the effect of testing if S, when sorted and case ignored, has every letter of the alphabet. 

Explanation of the 6 byter coming in maybe 12 hours.

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

JavaScript (ES6), 80

I wrote out a solution virtually identical to edc65's entry before I scrolled to the bottom of the page and saw it was already there! Anyway, here's still another alternate JavaScript approach:

s=>[...Array(26)].every((v,i)=>~s.search(RegExp(String.fromCharCode(i+65),"i")))

My original solution (83) with toUpperCase, before I got the idea to use a case-insensitive RegExp from Cᴏɴᴏʀ O'Bʀɪᴇɴ's solution:

s=>[...Array(26)].every((v,i)=>~s.toUpperCase().indexOf(String.fromCharCode(i+65)))

The code uses every to test whether or not every value of i from 0 to 25 casues the expression String.fromCharCode(i+65) to produce a character that exists in the input string (according to a case-insensitive match).

\$\endgroup\$
1
  • \$\begingroup\$ I wanted to use .every but I couldn't figure out! :D Nice solution! \$\endgroup\$ – Conor O'Brien Dec 10 '15 at 19:26
1
\$\begingroup\$

Mathematica, 44 bytes

Characters@ToLowerCase@#~SubsetQ~Alphabet[]&

Usage:

In[1]:= Characters@ToLowerCase@#~SubsetQ~Alphabet[]&[
         "The quick brown fox jumps over the lazy doge."]

Out[1]= True
\$\endgroup\$
1
\$\begingroup\$

PHP, 92 bytes

The code:

echo!array_diff(range(a,z),array_keys(array_count_values(str_split(strtolower($argv[1])))));

There is not much golfing in it (the clear code is 102 bytes).

Prepend it with the PHP marker <?php (technically, it is not part of the code), put it into a file (is-it-a-pangram.php) and run it like:

$ php -d error_reporting=0 is-it-a-pangram.php '123abcdefghijklm NOPQRSTUVWXYZ321'

Or put the code directly in the command line:

$php -d error_reporting=0 '... the code here ...' AbCdEfGhIjKlMnOpQrStUvWxYz

It outputs 1 when the input string is a pangram; it doesn't output anything when the string is not a pangram. This is the default representation for boolean values in PHP.

An unambiguous output can be obtained by adding a + sign in front of the echo-ed expression (echo+!array_diff(...);). This way, the boolean value is converted to an integer (1 or 0).

How the code works

It makes the input string lowercase, splits it to individual characters, count the number of occurrences for each character that appears in the string, then makes the difference between the alphabet characters (a to z) and the characters found in the string. If the difference is not empty then not all the letters are found in the string (i.e. the string is not a pangram).

The code and the testcase (using the samples provided in the question) can be found on Github.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ You actually don't need the array_keys(array_count_values()) at all, and can get the score down to 63. tio.run/… Otherwise your answer is virtually the same as the second one I just posted for this! :) \$\endgroup\$ – 640KB Mar 12 '19 at 17:53
  • \$\begingroup\$ Indeed, sometimes I am not seeing the simplest solution and I tend to find complicated ways to solve the problems. \$\endgroup\$ – axiac Mar 13 '19 at 10:39
1
\$\begingroup\$

Java, 97 96 bytes

boolean s(String t){for(int a=65;++a<91;)if(t.toUpperCase().indexOf(a)<0)return 1<0;return 0<1;}

Assumes ASCII or compatible character encoding.

It loops over the capital letters (65-90), checking if each one is present with indexOf, which takes an int.

\$\endgroup\$
2
  • \$\begingroup\$ ++a<=90; can be shortened by one byte to ++a<91;. \$\endgroup\$ – Kevin Cruijssen May 17 '16 at 14:11
  • \$\begingroup\$ @KevinCruijssen Thanks. I've updated my answer based on your suggestion. \$\endgroup\$ – rgettman May 17 '16 at 19:35
1
\$\begingroup\$

R, 97 92 bytes

Not competing with @mnel's excellent answer, but nevertheless :

function(s){a=strsplit(s,"")[[1]];m=match;sum(unique(c(m(a,letters,0),m(a,LETTERS,0))))=351}

This function takes your input, breaks it into its letters (strsplit), matches (match function, obviously) each letters of the input with both letters and LETTERS, built-in constant containing lowercases and uppercases letters. The unmatched positions are replaced with 0's.

Then, it eliminates all the redundant positions (unique), and make their sum. Considering there are 26 letters in the alphabet and the 1-indexed positions in R, if all the letters are contained at least once in your input, the sum of their positions will be 1+2+...+25+26, which is 351

- 5 bytes thanks to @plannapus !

\$\endgroup\$
1
  • \$\begingroup\$ if you were defining a as strsplit(s,"")[[1]] you wouldn't have to repeat a[[1]] twice and thus save 5 bytes. \$\endgroup\$ – plannapus Nov 1 '16 at 8:06
1
\$\begingroup\$

Java 8, 69 bytes

s->s.toUpperCase().chars().distinct().filter(c->c>64&c<91).count()>25

Alternatives with same byte count:

s->s.chars().map(c->c&~32).distinct().filter(c->c>64&c<91).count()>25
s->s.chars().map(c->c|32).distinct().filter(c->c>96&c<123).count()>25

Try it online.

Similar to @ProgramFOX' C# answer.

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

Japt -!, 6 4 bytes

;CkU

Try it here

\$\endgroup\$
1
  • \$\begingroup\$ Due to a quirk in how S.k() works, you actually don't need the v :-) \$\endgroup\$ – ETHproductions Feb 23 '18 at 20:27
1
\$\begingroup\$

PHP, 59 56 bytes

<?=!array_diff(range(a,z),str_split(strtolower($argn)));

Try it online!

Alt version 67 bytes

<?=array_intersect($a=range(a,z),str_split(strtolower($argn)))==$a;

Try it online!

Call with php -nF input is from STDIN.

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

APL(NARS), 22 chars, 44 bytes

{∧/×↑+/↑¨{+/⍵=⎕a⎕A}¨⍵}

test:

  h←{∧/×↑+/↑¨{+/⍵=⎕a⎕A}¨⍵}
  h 'abcdefghijklmnopqrstuvwXYZ'
1
  h '123abcdefghijklm NOPQRSTUVWXYZ321'
1
  h 'public static void main(String[] args)'
0
  h 'The quick brown fox jumped over the lazy dogs. BOING BOING BOING'
1
\$\endgroup\$
1
\$\begingroup\$

Perl 5 -p, 30 28 bytes

@a{lc=~/[a-z]/g}++;$_=26==%a

Try it online!

\$\endgroup\$
1
  • \$\begingroup\$ -2 bytes by using the \pL shorthand for \p{L} instead of [a-z] (as I see you already did in your 22 byte module-requiring answer): ++@a{uc=~/\pL/g};$_=%a==26 Try it online! – it ends with its own length now :-) Also, why does this only require -p and not -p0? \$\endgroup\$ – Deadcode Apr 11 at 20:12
1
\$\begingroup\$

Charcoal, 9 6 bytes

⬤β№↧θι

Try it online! Link is to verbose version of code. Outputs a Charcoal boolean (- for true, nothing for false). Just checks that each lowercase letter appears at least once in the lowercase input Explanation:

 β      Lowercase alphabet
⬤       All characters satisfy
  №     (Non-zero) count of
     ι  Current lowercase letter in
    θ   First input
   ↧    Lowercased
        Implicitly print
\$\endgroup\$
1
\$\begingroup\$

GolfScript, 18 bytes

Port of the GS2 answer.

{32|}%[123,97>]\-!

Try it online!

Explanation

{   }%             # Map for every item in input
 32|               # Toggle the 6th bit (turning capitalization on)
      [123,        # Generate exclusive range from '}' (previous 'z') to 0
           97>]    # Select all that are >= 'a'
                   # Yielding the lowercase alphabet
               \-  # Set difference between them
                 ! # Negate the value
\$\endgroup\$
0
1
\$\begingroup\$

Dyalog APL, 13 bytes

∧/⎕A∊1(819⌶)⊢

explanation:

1(819⌶)⊢ ⍝ uppercase
⎕A∊      ⍝ check if all uppercase letters belong to the string
∧/        ⍝ AND reduction of the boolean vector
\$\endgroup\$
2
1
\$\begingroup\$

Burlesque, 16 bytes

zzXX@azr@Jx/IN=s

Try it online!

                                                 [IN]
zz    # Lowercase input                          [in]
XX    # Split into characters                    [i,n]
@azr@ # Push lowercase alphabet                  [i,n],[a,..,z]
Jx/   # Duplicate and bring the input to the top [a,..,z],[a,..,z],[i,n]
IN    # Intersection of the two                  [a,..,z],alpha IN input
=s    # Is equal to the alphabet when sorted     1/0
\$\endgroup\$

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.