Regex and Pangrams

I have been racking myself over the coals with this one for three days. I’m not looking for a solution; rather, clarification of my inkling.
The game is that you need to write code to determine if a string is a pangram or not.

I wrote the one below.

function isPangram(string){
  return /[A-Za-z]\s\D/.test(string)
}

I am registering the following string as false:
‘ABCD45EFGH,IJK,LMNOPQR56STUVW3XYZ’
and the following string as true:
‘Detect Pangram’

Neither of these make sense to me as my regex explicitly asks for any number in the alphabet regardless of case. I have two theories:

  1. I am using the improper method. I don’t believe I am but something gnaws at me and says that test() is not the correct route to go and I should use something like an if/else
    2.I should be altering “string” in some way. The behavior of strings in the failed test leads me to believe that I should be working with the form of the string.

At the very least I’d like to know if my problem is with the regex itself or with something surrounding it.

Thanks for anything.

well I just glanced and I’m not familiar with the exercise but you do need to add a “g” (global) modifier => docs
look below for code example of a modifier that uses, g

function isPangram(string){
  return /[A-Za-z]\s\D/g.test(string)
}

– edit
The global modifier allows the method to search past the first match or globally as in find multiple matches :slight_smile:

\D from the docs:
Find a non-digit character
\s: without any indicator for how many will want to find a explicit match you need to put a count modifier such as {n} where n is equal to the number of matches you want or any of the other ones suchas *, ?, or + – so basically your regex needs that in order to return true

just to point that at out, please look at the reference link I posted last comment, sorry for not posting this initially.

— EDIT and again sorry for not answering your question but check the docs on modifiers and other info regarding symbols and backslashed characters and there meaning.

Namaste :slight_smile:

in your regex there is a space character \s that this string doesnt have, so it is normal it will test as false

your regex says “one letter followed by a space followed by non digit character”, if in the string there is this pattern it will test true, you may want to play a bit with something line regex101.com

Regex isn’t the right tool at all here: it is designed to match patterns that appear in a specific order in text.

But with a pangram, you are checking if every one of the characters a-z appear anywhere in a string of characters. That string can be literally anything, and even if all the characters are present the could occur in any order.

I would build a Set.
Iterate over each character one by one and add to set only if a letter.
If set.size === 26 then stop.

Sets are perfect for this because if you have duplicates it will just overwrite. Thus enforcing 26 unique characters.

references: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set

2 Likes

Thanks for the advice about set(). I’m still puzzled by a last test.
ABCD45EFGH,IJK,LMNOPQR56STUVW3XYZ
I can’t seem to bypass the numbers and those are the only elements standing in the way of passing. I thought using \W would be enough. Does it have to do with the regex I’m using or is it the code around it?

let str = string.replace(/\W/gi, "").toLowerCase();
let arr = str.split('');
let newSet = new Set(arr);
if(newSet.size === 26){
return true
} else {
return false
}
}

\w is the same as [A-Za-z0-9_], so \W is just anything not in that range of characters. [^A-Z] is “not in the range of characters A-Z”

Example string.

const myStr = ‘ABABCDFF’;

const mySet = new Set(Array.from(myStr));

// Set(5) {"A", "B", "C", "D", "F"}

I got the solution, but I feel I am repeating myself a bit and could consolidate my code. Would someone mind looking at my solution and providing insight toward my query? Much obliged. Code below.
My biggest concern is that I’m using replace() twice. I was trying to go step by step but there’s probably a more concise way of getting the things I want to get.
Thank you!

function isPangram(string){
//replace all non-alphabet elements and transform to lowercase
let str = string.replace(/\W/gi, "").toLowerCase();
//remove all embedded numerals within string
let arr = str.replace(/[0-9]/g, "")
//convert to set in order to have no repeating letters
let newSet = new Set(arr);
//once in set triple-equal to 26 to ensure legitimacy of pangram and return as boolean
if(newSet.size === 26){
return true
} else {
return false
}

}

I think the following would be OK unless I am missing an edge case:

function isPangram(string) {
  //replace all non-alphabet character and transform to lowercase
  let str = string.replace(/[^a-z]/gi, "").toLowerCase();
  //convert to set in order to have no repeating letters
  let newSet = new Set(str);
  //once in set triple-equal to 26 to ensure legitimacy of pangram and return as boolean
  return newSet.size === 26;
}

Nice and clean.

Only edge case I can think of is a string that is a billion chars long and it had duplicates.

In that case I would check one letter at a time and exit the loop as soon as the set.size === 26.