10

I am trying to write a REGEX to test for a PANGRAM. I can do it the traditional way, but cannot seem to solve it for more than 90% of my tests with a regular expression.

Input: string

Output: true || false

function isPangram(string){ 
   return ___________________.test(string) 
}

Test Results so far.

6/10 /([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, \s]+)/i

6/10 /[a-z]{1}/i

6/10 /[a-z]/i

6/10 /[a-z]+/i

9/10 /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/i only failed against abcdefghijklmopqrstuvwxyz

6/10 /[\w.]+/

Any help or advice is greatly appreciated.

Vontei
  • 1,727
  • 2
  • 14
  • 16

9 Answers9

27
  1. Convert the string to lowercase
  2. Use regex to extract all the unique alphabets from string
  3. Check if the no of unique alphabets are 26

Code:

function isPangram(string) {
    var regex = /([a-z])(?!.*\1)/g;
    return (string.match(regex) || []).length === 26;
}

Regex101

var regex = /([a-z])(?!.*\1)/g;

function check() {
  var val = document.getElementById('text').value.toLowerCase();

  alert(val.match(regex).length == 26);
}
<input type="text" id="text" />

<button onclick="check()">Check</button>
Tushar
  • 85,780
  • 21
  • 159
  • 179
  • 1
    Check the question - it provides the template for the function. So you cannot put arbitrary js, the answer must be a regex only. – zerkms Sep 14 '15 at 04:55
  • 1
    Technically it still does not qualify the requirements. The challenge requires you to only substitute the `_______` part and not modify anything else. – zerkms Sep 14 '15 at 04:58
  • this is an awesome approach, and also passed another round of testing. But it did not pass for : ' AbCdEfGhIjKlM zYxWvUtSrQpOn' or ' How quickly daft jumping zebras vex.' Tricky – Vontei Sep 14 '15 at 06:28
  • @Vontei The both strings are PANGRAMS and it's showing as _true_ when given input to the above demo, it's working as expected. Isn't it? – Tushar Sep 14 '15 at 06:33
  • @PraveenKumar it does not answer the question asked though :-D – zerkms Oct 12 '15 at 00:36
  • Could you explain the regex that you used? – JacobTheKnitter Mar 07 '22 at 16:32
12

If you are looking for Non-RegExp Solution

const isPangram = (string) => 
     new Set(string.toLowerCase().match(/[a-z]/g)).size === 26;

console.log(isPangram("abcdefghijklmnopqrstuvwxyz"));  //true
console.log(isPangram("The Quick Brown Fox Jumps over the lazy dog")); //true
Mohammad Faisal
  • 2,144
  • 15
  • 26
10

This would be a correct answer for the challenge:

function isPangram(string){ 
   return /(?=.*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)./i.test(string) 
}

It uses lookaheads with every letter to check that they are somewhere in the passed string.

zerkms
  • 249,484
  • 69
  • 436
  • 539
3

using for..of loop & includes:

function isPangram(sentence) {
let lowerCased = sentence.toLowerCase();
for (let char of 'abcdefghijklmnopqrstuvwxyz') {
    if (!lowerCased.includes(char)) {
        return false;
     }
  }
 return true;
}
2

As a single regex:

/(?:(?=(.*?([a-z]))(?!.*\2))\1){26}/i

Test it at regex101.

A breakdown:

/
  (?:               // non-capturing group
    (?=             // look-ahead assertion

      (.*?([a-z]))  // match a letter, preceded by as few characters as possible
      (?!.*\2)      // assert that this letter does not appear in the remainder of the string
                    // (in aggregate, this will find the last occurrence of each letter)

    )\1             // actually match that group (this is done to prevent backtracking)
  ){26}             // match 26 times (once for each letter)
/i                  // match case-insensitively

If the regex engine you're using supports atomic grouping (e.g. PCRE), this can be written somewhat more concisely:

/(?>.*?([a-z])(?!.*\1)){26}/i

regex101.

primo
  • 1,392
  • 16
  • 27
2

Given a string, detect whether or not it is a pangram. Return True if it is, False if not. Ignore numbers and punctuation. [adding case-insensitivity based on the regex code provided by @Tushar]

//Detect Pangram
function isPangram(string){
// character set capturing group with negative lookahead
  let regex = /([a-z])(?!.*\1)/gi;
  return (string.match(regex)).length === 26;
}

console.log(isPangram("The quick brown fox jumps over the lazy dog."));// true
console.log(isPangram("This is not a pangram."));// false
console.log(isPangram("Pack my box with five dozen liquor jugs."));// true
console.log(isPangram("This isn't a pangram!"));// false
console.log(isPangram("Detect Pangram"));// false
console.log(isPangram("How quickly daft jumping zebras vex."));// true
G Dube
  • 127
  • 7
0
function isPangram(input) {
  if(input.length < 26) {
    return false;
  }
  const letters = 'abcdefghijklmnopqrstuvwxyz';
  return Array.from(new Set(input.toLowerCase().split('').filter(i => i.trim()))).sort().join('') === letters;  
}

console.log(isPangram("The String is abcdefghijklumnopqrstvwxyz")); //true
-1

const isPangram = (string) => 
     new Set(string.toLowerCase().match(/[a-z]/g)).size === 26;

console.log(isPangram("This is not a pangram."));  //false
console.log(isPangram("The Quick Brown Fox Jumps over the lazy dog")); //true
  • 2
    Welcome to SO! Please edit your answer and add a little textual explanation to it: Why and how does it work and what makes it differ from the other answers given. – ahuemmer Apr 05 '22 at 11:50
-3
function isPangram(string){

  let lc = string.toLowerCase()
 let alphabet = "abcdefghijklmnopqrstuvwxyz"

   return alphabet.split("").filter(c => lc.indexOf(c) === -1).length === 0;
}
  1. Lower case the string
  2. Create a string with the alphabet
  3. split the alphabet
  4. Using filter() with a mini function that will verify that there are 0 false statements in it (filter it so there is 0 (zero) false statement (-1) in the new array that the filter method creates ".lengeth === 0" makes sure there is no false statement )