10

I want to create a function which takes a string as input and check whether the string is pangram or not (pangram is a piece of text which contains every letter of the alphabet).

I wrote the following code, which works, but I am looking for an alternative way to do it, hopefully a shorted way.

import string

def is_pangram (gram):
    gram = gram.lower()
    gram_list_old = sorted([c for c in gram if c != ' '])
    gram_list = []
    for c in gram_list_old:
        if c not in gram_list:
            gram_list.append(c)
    if gram_list == list(string.ascii_lowercase): return True
    else: return False

I feel like this question might be against the rules of this website but hopefully it isn't. I am just curious and would like to see alternative ways to do this.

dwitvliet
  • 7,242
  • 7
  • 36
  • 62
  • Can there be punctuation and whitespace in 'piece of text'? – wwii Jul 16 '14 at 03:21
  • I didn't think of that. In the code above, I delete all whitespace, so I would do the same to punctuation. –  Jul 16 '14 at 03:29

15 Answers15

19
is_pangram = lambda s: not set('abcdefghijklmnopqrstuvwxyz') - set(s.lower())

>>> is_pangram('abc')
False
>>> is_pangram('the quick brown fox jumps over the lazy dog')
True
>>> is_pangram('Does the quick brown fox jump over the lazy dog?')
True
>>> is_pangram('Do big jackdaws love my sphinx of quartz?')
True

Test string s is a pangram if we start with the alphabet, remove every letter found in the test string, and all the alphabet letters get removed.

Explanation

The use of 'lambda' is a way of creating a function, so it's a one line equivalent to writing a def like:

 def is_pangram(s):
     return not set('abcdefghijklmnopqrstuvwxyz') - set(s.lower())

set() creates a data structure which can't have any duplicates in it, and here:

  • The first set is the (English) alphabet letters, in lowercase
  • The second set is the characters from the test string, also in lowercase. And all the duplicates are gone as well.

Subtracting things like set(..) - set(..) returns the contents of the first set, minus the contents of the second set. set('abcde') - set('ace') == set('bd').

In this pangram test:

  • we take the characters in the test string away from the alphabet
  • If there's nothing left, then the test string contained all the letters of the alphabet and must be a pangram.
  • If there's something leftover, then the test string did not contain all the alphabet letters, so it must not be a pangram.

  • any spaces, punctuation characters from the test string set were never in the alphabet set, so they don't matter.

set(..) - set(..) will return an empty set, or a set with content. If we force sets into the simplest True/False values in Python, then containers with content are 'True' and empty containers are 'False'.

So we're using not to check "is there anything leftover?" by forcing the result into a True/False value, depending on whether there's any leftovers or not.

not also changes True -> False, and False -> True. Which is useful here, because (alphabet used up) -> an empty set which is False, but we want is_pangram to return True in that case. And vice-versa, (alphabet has some leftovers) -> a set of letters which is True, but we want is_pangram to return False for that.

Then return that True/False result.

is_pangram = lambda s: not set('abcdefghijklmnopqrstuvwxyz') - set(s.lower())
#      Test string `s`
#is a pangram if
#                           the alphabet letters 
#                                                             minus 
#                                                               the test string letters
#                   has NO leftovers
TessellatingHeckler
  • 27,511
  • 4
  • 48
  • 87
  • 1
    Wow, this method is great! I still don't understand it at the moment but will read the docs and hopefully understand it. –  Jul 16 '14 at 03:31
  • 1
    Thank you very much! Really appreciate the effort. –  Jul 16 '14 at 03:39
4

You can use something as simple as:

import string
is_pangram = lambda s: all(c in s.lower() for c in string.ascii_lowercase)
dwitvliet
  • 7,242
  • 7
  • 36
  • 62
  • 1
    Nice! I had a feeling it could be done much shorter. –  Jul 16 '14 at 02:51
  • By the way, what does `all` do here? –  Jul 16 '14 at 02:52
  • 1
    `all()` returns `True` if all elements in the list are `True`. See [documentation](https://docs.python.org/2/library/functions.html#all) for definition. – dwitvliet Jul 16 '14 at 02:53
  • brackets can be removed in the `all()` – monkut Jul 16 '14 at 04:13
  • @monkut Why? Because of lambda expression? – NAND Jun 09 '20 at 19:38
  • `all()` without brackets will create/use a generator expression, providing the `[]` will create a list evaluated by all. There are discussions of which is faster in certain cases, but imho if you data is small the bracketless solution is cleaner. – monkut Jun 10 '20 at 00:21
3

Sets are excellent for membership testing:

>>> import string
>>> candidate = 'ammdjri * itouwpo ql ? k @ finvmcxzkasjdhgfytuiopqowit'
>>> ascii_lower = set(string.ascii_lowercase)

Strip the whitespace and punctuation from the candidate then test:

>>> candidate_lower = ascii_lower.intersection(candidate.lower())
>>> ascii_lower == candidate_lower
False

Find out what is missing:

>>> ascii_lower.symmetric_difference(candidate_lower)
set(['b', 'e'])

Try it again but add the missing letters:

>>> candidate = candidate + 'be'
>>> candidate_lower = ascii_lower.intersection(candidate.lower())
>>> ascii_lower == candidate_lower
True
>>>
wwii
  • 23,232
  • 7
  • 37
  • 77
2
 def pangram(word):
      return all(chr(c+97) in word for c in range(25))
Wheat
  • 31
  • 6
1

How about simply check whether each one of the lowercased alphabet is in the sentence:

text = input()
s = set(text.lower())

if sum(1 for c in s if 96 < ord(c) < 123) == 26:
    print ('pangram')
else:
    print ('not pangram')

or in a function:

def ispangram(text):
    return sum(1 for c in set(text.lower()) if 96 < ord(c) < 123) == 26
alvas
  • 115,346
  • 109
  • 446
  • 738
1

Here is another definition:

def is_pangram(s):
    return len(set(s.lower().replace(" ", ""))) == 26
1

I came up with the easiest and without using module programe.

def checking(str_word):
b=[]
for i in str_word:
    if i not in b:
        b.append(i)
b.sort()
#print(b)
#print(len(set(b)))
if(len(set(b))>=26):
    print(b)
    print(len(b))
    print(" String is  pangram .")

else:
        print(" String isn't pangram .")
    #b.sort()
#print(b)


str_word=input(" Enter the String :")
checking(str_word)
sameer_nubia
  • 721
  • 8
  • 8
0

I see this thread is a little old, but I thought I'd throw in my solution anyway.

import string

def panagram(phrase):
    new_phrase=sorted(phrase.lower())
    phrase_letters = ""
    for index in new_phrase:
        for letter in string.ascii_lowercase:
            if index == letter and index not in phrase_letters:
                phrase_letters+=letter
    print len(phrase_letters) == 26

or for the last line:

    print phrase_letters == string.ascii_lowercase
Trent Roberts
  • 35
  • 1
  • 5
0
def panagram(phrase):
alphabet="abcdefghiklmnopqrstuvwxyz"
pharseletter=""
for char in phrase:
    if char in aphabet:
        phraseletter= phraseletter + char
for char in aplhabet:
    if char not in phrase:
        return false
0
import string
def ispangram(str, alphabet=string.ascii_lowercase):
    alphabet = set(alphabet)    
    return alphabet <= set(str.lower())

or more simpler way

def ispangram(str):
    return len(set(str.lower().replace(" ", ""))) == 26
0
import string

def is_pangram(phrase, alpha=string.ascii_lowercase):
     num = len(alpha)
     count=0

for i in alpha:
    if i in phrase:
        count += 1
return count == num
0
def panagram(str1):
    str1=str1.replace(' ','').lower()
    s=set(str1)
    l=list(s)
    if len(l)==26:
        return True
    return False




str1='The quick brown fox jumps over the dog'
q=panagram(str1)
print(q)

True

ravi tanwar
  • 598
  • 5
  • 16
0
import string
def ispangram(str1,alphabet=string.ascii.lowercase):  
for myalphabet in alphabet:
    if myalphabet not in str1:
        print(it's not pangram)
        break
    else:
        print(it's pangram)

Execute the command:

ispangram("The quick brown fox jumps over the lazy dog")

Output: "it's pangram." Hint: string.ascii_lowercase returns output

abcdefghijklmnopqrstuvwxyz
Kim
  • 4,080
  • 2
  • 30
  • 51
suma
  • 1
-1
import java.io.*;
import java.util.*;
import java.text.*;
import java.math.*;
import java.util.regex.*;

public class Solution {

    public static void main(String[] args) {

        String s;
        char f;
         Scanner in = new Scanner(System.in);
        s = in.nextLine();

        char[] charArray = s.toLowerCase().toCharArray();
        final Set set = new HashSet();

        for (char a : charArray) {
            if ((int) a >= 97 && (int) a <= 122) {
                f = a;
                set.add(f);
            }

        }
        if (set.size() == 26){
            System.out.println("pangram");
        }
        else {
            System.out.println("not pangram");
        }
    }
}
-1
import string
import re
list_lower= list(string.lowercase);
list_upper=list(string.uppercase);
list_total=list_lower + list_upper ;
def is_panagram(temp):
    for each in temp:
        if each not in list_total :
            return 'true'
sample=raw_input("entre the string\n");
string2=re.sub('[^A-Za-z0-9]+', '', sample)
ram=is_panagram(string2);
if ram =='true':
    print "sentence is not a panagram"
else:`enter code here`
    print"sentece is a panagram"