|
| 1 | +# Bit field |
| 2 | + |
| 3 | +```javascript |
| 4 | +const A_LCASE = 97; |
| 5 | +const A_UCASE = 65; |
| 6 | +const ALL_26_BITS_SET = 67108863; |
| 7 | + |
| 8 | +export function isPangram(input) { |
| 9 | + let phrasemask = 0; |
| 10 | + [...input].forEach((letter) => { |
| 11 | + if (letter >= 'a' && letter <= 'z') |
| 12 | + phrasemask |= 1 << (letter.charCodeAt(0) - A_LCASE); |
| 13 | + else if (letter >= 'A' && letter <= 'Z') |
| 14 | + phrasemask |= 1 << (letter.charCodeAt(0) - A_UCASE); |
| 15 | + }); |
| 16 | + return phrasemask == ALL_26_BITS_SET; |
| 17 | +} |
| 18 | +``` |
| 19 | + |
| 20 | +This solution uses the [ASCII][ascii] value of the letter to set the corresponding bit position. |
| 21 | + |
| 22 | +Some [const][const]ants are defined for readability in the function. |
| 23 | +The ASCII value for `a` is `97`. |
| 24 | +The ASCII value for `A` is `65`. |
| 25 | +The value for all of the rightmost 26 bits being set is `67108863`. |
| 26 | + |
| 27 | +- [Spread syntax][spread-syntax] is used to make an [`Array`][array] of the characters in the `input`. |
| 28 | +- The `Array` method [`forEach`][foreach] loops through the characters and looks for a character being `a` through `z` or `A` through `Z`. |
| 29 | +- If a letter is found, then its ASCII value is taken by the [`charCodeAt`][charcodeat] method. |
| 30 | + |
| 31 | +```exercism/note |
| 32 | +`charCodeAt` actually returns the UTF-16 code unit for the character, which is an integer between `0` and `65535`. |
| 33 | +For the letters `a`-`z` and `A`-`Z`, the UTF-16 number is the same value as the ASCII value. |
| 34 | +``` |
| 35 | + |
| 36 | +- If the lowercase letter is subtracted by `97`, then `a` will result in `0`, because `97` minus `97` equals `0`. |
| 37 | + `z` would result in `25`, because `122` minus `97` equals `25`. |
| 38 | + So `a` would have `1` [shifted left][shift-left] 0 places (so not shifted at all) and `z` would have `1` shifted left 25 places. |
| 39 | +- If the uppercase letter is subtracted by `A`, then `A` will result in `0`, because `65` minus `65` equals `0`. |
| 40 | + `Z` would result in `25`, because `90` minus `65` equals `25`. |
| 41 | + So `A` would have `1` [shifted left][shift-left] 0 places (so not shifted at all) and `Z` would have `1` shifted left 25 places. |
| 42 | + |
| 43 | +In that way, both a lowercase `z` and an uppercase `Z` can share the same position in the bit field. |
| 44 | + |
| 45 | +So, for an integer, if the values for `a` and `Z` were both set, the bits would look like |
| 46 | + |
| 47 | +``` |
| 48 | + zyxwvutsrqponmlkjihgfedcba |
| 49 | +00000010000000000000000000000001 |
| 50 | +``` |
| 51 | + |
| 52 | +We can use the [bitwise OR operator][or] to set the bit. |
| 53 | +After the loop completes, the function returns if the `phrasemask` value is the same value as when all `26` bits are set, which is `67108863`. |
| 54 | + |
| 55 | +[ascii]: https://www.asciitable.com/ |
| 56 | +[const]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const |
| 57 | +[spread-syntax]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax |
| 58 | +[array]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array |
| 59 | +[foreach]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach |
| 60 | +[charcodeat]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charCodeAt |
| 61 | +[shift-left]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Left_shift |
| 62 | +[or]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_OR |
0 commit comments