// Package pangram is a small library for checking if a phrase is a pangram
package pangram
const alphamask int = 0b11111111111111111111111111
// IsPangram checks if a phrase is a pangram
func IsPangram(phrase string) bool {
phrasemask := 0
length := len(phrase)
for i := 0; i < length; i++ {
letter := phrase[i]
if letter > 96 && letter < 123 {
phrasemask |= 1 << (letter - 97)
} else if letter > 64 && letter < 91 {
phrasemask |= 1 << (letter - 65)
}
}
return phrasemask == alphamask
}
This solution uses the ASCII value of the letter to set the corresponding bit position.
The constant alphamask is the value for the rightmost 26 bits of an int being set.
It is set using a binary literal.
The blank bit field phrasemask is defined to keep track of the used letters.
The ways to iterate characters are by Unicode runes, or by each letter being a string, or by each letter being a byte.
The runes are from range on a string, the strings from Split(), and the bytes from indexing into the string.
Another way to iterate runes is to convert the string to a rune slice and range on it.
The difference between ranging on a rune slice vs ranging on a string is that the index returned from a string is the position of the next rune in bytes,
not which rune it is.
For example, if the first unicode character is two bytes, then the second unicode character index will be 2 when ranging on a string and 1 when ranging on a rune slice.
As of the time of this writing we can iterate bytes, since all of the characters are ASCII.
The string is looped through its characters, looking for a character being a through z or A through Z.
-
The ASCII value for
ais97, and forzis122. -
The ASCII value for
Ais65, and forZis90. -
If the lowercase letter is subtracted by
97, thenawill result in0, because97minus97equals0.zwould result in25, because122minus97equals25. Soawould have1shifted left 0 places (so not shifted at all) andzwould have1shifted left 25 places. -
If the uppercase letter is subtracted by
A, thenAwill result in0, because65minus65equals0.Zwould result in25, because90minus65equals25. SoAwould have1shifted left 0 places (so not shifted at all) andZwould have1shifted left 25 places.
In that way, both a lowercase z and an uppercase Z can share the same position in the bit field.
So, for a 32-bit unsigned integer, if the values for a and Z were both set, the bits would look like
zyxwvutsrqponmlkjihgfedcba
00000010000000000000000000000001
We can use the bitwise OR operator to set the correct bit for the letter's position in the alphabet.
After the loop completes, the function returns if the phrasemask value is the same value as when all 26 bits are set.