What is the problem with my pangram javascript? - javascript

Pangram is a function that gets an input and check it if it has all alphabet ,This is my code i used ASCII code :
function pangram(x) {
var a;
for (var i = 97; i < 122; i++) {
a = "&#" + i + ";";
if (x.toLowerCase().includes(a) !== true) {
break;
}
}
if (i === 122) {
return true
} else {
return false
}
}
I think the problem is a = "&#" + i + ";" ; but i don't know why it can be a problem , it should work ...

You need to use charCodeAt() instead of making a manual one. Replace if condition to this :
if(x.toLowerCase().includes(String.fromCharCode(i))!==true)

You have come close to the answer, yet there are a few issues with the code,
a = "&#" + i + ";";, what does this do? You can use String.fromCharCode(65); to get the character for a given ASCII value. More info: https://www.w3schools.com/jsref/jsref_fromcharcode.asp
You can just exit the loop and the function if a character was not found, no point continuing after that point.
function pangram(x) {
var a;
for (var i = 97; i < 122; i++) {
a = String.fromCharCode(i);;
if (x.toLowerCase().includes(a) !== true) {
// if atleast one letter was not found, we exit the function and the loop
return false;
}
}
// if it comes here, that means all the letters were found
return true;
}
var isPangram = pangram("The quick brown fox jumps over the lazy dog");
console.log(isPangram);

Related

Program to decode the encoded string according to the pattern shown (JavaScript)

Encoding Input Data: ABC - Output: ZBYX
The encoding happens such that the odd numbered letters of the English alphabet are replaced by their alphabetic opposite, even numbered letters are replaced by a combination of that same letter and it's alphabetic opposite (ie. as shown above 'B' is even numbered alphabet so it got replaced as 'BY', A is replaced by Z, C is replaced by X)
I need to decode the encoded output data to get the input (the reverse logic). I wrote the below function but it doesn't quite give me the expected output for all test cases. (eg: When the input is ZBYX, output comes up correctly as ABC, but in other cases such as:
JQPLO (input) - output comes as QJKL (supposed to come as JKL)
NMLPK (input) - output comes as MNOP (supposed to come as NOP)
)
How should I refactor the below code so that I get the expected output for all test cases?
let alpha="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
function decode(str){
let answer=""
for(let i=0;i<str.length;i++){
if(alpha.indexOf(answer[answer.length-1])%2==0){
if((alpha.indexOf(str[i])+1)%2==0){
continue
}
answer+=alpha[alpha.length-(alpha.indexOf(str[i])+1)]
}else{
answer+=alpha[alpha.length-(alpha.indexOf(str[i])+1)]
}
}
return answer
}
The trick for decoding is, if you get to an even letter l AND the next letter is the opposite of l, then you add l to the decoded output and skip the next letter. Otherwise, you need to just add the opposite of l to the output.
I would recommend trying it yourself before reading the code below, but the below code passed all the test cases you provided.
let alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
function isEven(c) {
return (alpha.indexOf(c) + 1) % 2 === 0;
}
function opposite(c) {
return alpha[alpha.length - alpha.indexOf(c) - 1];
}
function encode(str) {
let answer = "";
for (let i = 0; i < str.length; i++) {
if (!isEven(str[i])) {
answer += opposite(str[i]);
} else {
answer += str[i];
answer += opposite(str[i]);
}
}
return answer;
}
function decode(str) {
let answer = "";
for (let i = 0; i < str.length; i++) {
if (isEven(str[i]) && str[i + 1] === opposite(str[i])) {
answer += str[i];
i++;
} else {
answer += opposite(str[i]);
}
}
return answer;
}
console.log(encode('ABC'));
console.log(decode('ZBYX'));
console.log(decode('NMLPK'));
console.log(decode('JQPLO'));
const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const decode = str => {
str = str.split("").reduce((p, c, i, arr) => {
if (alphabet.indexOf(arr[i + 1]) % 2 !== 0)
p += alphabet[25 - alphabet.indexOf(c)];
return p
}, "");
return str;
}
console.log(decode("ZBYX"));
console.log(decode("JQPLO"));
console.log(decode("NMLPK"));
const encode = str => {
str = str.split("").reduce((p, c) => {
if (alphabet.indexOf(c) % 2 !== 0)
p += c + alphabet[25 - alphabet.indexOf(c)];
else
p += alphabet[25 - alphabet.indexOf(c)];
return p
}, "");
return str
}
console.log(encode("ABC"));
I eventually figured out a solution based off my initial program in the question, I just don't know how it works but it passed all test cases; Thanks for all the other answers here, appreciate the effort guys!
here's my updated code:
function decode(str){
try{
let answer=""
if(!(/^[A-Z]+$/).test(str)){
throw Error("Input must only contain upper case letters")
}
for(let i=0;i<str.length;i++){
if(alpha.indexOf(answer[answer.length-1])%2==0){
if((alpha.indexOf(str[i])+1)%2==0){
continue
}
}else{
if(str.length>4)answer=answer.slice(-1)
}
answer+=alpha[alpha.length-(alpha.indexOf(str[i])+1)]
}
return answer
} catch (err){
console.log(err)
}
}
I just added a condition to check for the string length given at the input under the else block, but I guess the other answers here were more logical than mine

Regular Expression to check- No more than 2 sequential numbers or characters and No more than 1 same numbers or characters-Javascript

I want to reject user input if it contains 2 sequential numbers or characters ,for example 1234,jkl, zyxw and if it contains more than 1 same numbers or characters like aaer,0000,aabb,pp22. Thank you for insights. I have regex for the second one but dont know how to combine the two expressions:
"([a-zA-Z0-9])\\1{1,}"
Doing this in regex is neither sound nor practical. However, you can easily check if your input contains a sequential (abc.. or cba) pattern using code like that:
function isSequencial(input) {
var numpattern = '0123456789012345789'; // match ascending/descending sequence of numbers.
var charpattern = 'ABCDEFGHIJKLMNOPQRSTUVWXYZYXWVUTSRQPONMLKJIHGFEDCBA'; // match ascending/descending sequence of letters.
for (var i = 0; i < input.length-1; i++) {
var shard = input.substring(i,i+2);
if(numpattern.indexOf(shard) != -1) {
console.log('sequential number pattern detected: ' + shard);
return true;
}
if (charpattern.indexOf(shard.toUpperCase()) != -1) {
console.log('sequential letter pattern detected: ' +shard);
return true;
}
}
return false;
}
console.log("isSequencial(a234):" + isSequencial("a234"));
console.log("isSequencial(azyx):" + isSequencial("azyx"));
console.log("isSequencial(xbc):" + isSequencial("xbc"));
console.log("isSequencial(2435):" + isSequencial("2435"));
This code can be optimized but is easy to understand and maintain since it does not try to do multiple things at once. You should be able to combine this with your existing approach.
The simplest solution for your first requirement would be to parse it, as with a regex it will be not that easy to set up, if at all possible.
Here I used charCodeAt (and check for both sequence/equal and duplicates characters)
var input1 = "1543abc3";
var input2 = "cba23DEf";
var input3 = "ba2354cd";
console.log('test 1');
testit(input1.split(''));
console.log('test 2');
testit(input2.split(''));
console.log('test 3');
testit(input3.split(''));
function testit (arr) {
var prev = arr[0].charCodeAt(0) + 1, prev2 = -1;
for (var i = 1; i < arr.length; i++) {
var arritem = arr[i].charCodeAt(0);
if ( (arritem == prev && arritem == (prev2+1)) || // abc
(arritem == (prev-2) && arritem == (prev2-3)) // cba
) {
console.log(' - sequence, more than 2: ', arr[i-2], arr[i-1], arr[i] );
//return false;
}
if (arr.indexOf(arr[i-1],i) > -1) {
console.log(' - duplicate, more than 1: ', arr[i-1] );
//return false;
}
prev2 = prev;
prev = arr[i].charCodeAt(0) + 1;
}
//return true;
}

Javascript Last Letter getting cut off

Alright, so basically this code passes in a sentence into the function and the function needs to figure out which word is longest to return. Everything works great except that the very last letter keeps getting cut off. So what would be a good solution to this problem?
function LongestWord(sen) {
sen = sen.toLowerCase();
var build = "";
var arr = [];
var longest = 0;
for(var i = 0; i < sen.length;i++){
var cur = sen.charCodeAt(i);
console.log(sen.charCodeAt(i))
if(i == sen.length - 1){
arr.push(build);
}
if(sen.charAt(i) === " "){
arr.push(build);
build = "";
}
if(cur >= 97 && cur <= 122){
build += String.fromCharCode(cur);
}
}
console.log(arr);
for(var e = 0; e < arr.length - 1;e++){
if(arr[e].length > arr[e + 1].length){
longest = arr[e];
}
else{
longest = arr[e + 1];
}
}
return longest;
}
// keep this function call here
// to see how to enter arguments in JavaScript scroll down
console.log(LongestWord("Johnny ErsoL"));
It returns "Johnny", which is correct, but this is what the Array looks like at the end.
[ 'johnny', 'erso' ]
Here's my suggestion ?
function LongestWord(sen) {
return sen.split(/\b/).filter(function(item) {
return item.trim().length;
}).sort(function(a,b) {
return b.length - a.length;
});
}
split the sentence on word boundary, then trim off empty spaces, finally sort by length of each word and return the sorted array.
Try replacing
for(var i = 0; i < sen.length;i++){
var cur = sen.charCodeAt(i);
console.log(sen.charCodeAt(i))
if(i == sen.length - 1){
arr.push(build);
}
if(sen.charAt(i) === " "){
arr.push(build);
build = "";
}
if(cur >= 97 && cur <= 122){
build += String.fromCharCode(cur);
}
}
with
arr=sen.split();
You have a for loop with e <arr.length -1. I don't think you need the -1.
I know you already found your answer, however I just wanted to show you an alternative to what you are doing.
To simplify your code and also make it more understandable, but also flexible, it's usually a good idea to make sure that every function does only one thing, or has a single responsability.
In your code, your LongestWord function has the responsability to identify what is a word and to find out which one is the longest.
What you could have done is create a function that knows how to tokenize a sentence into words:
function forEachWordsIn(str, callback) {
var rx = /\b(\w+?)\b/g,
match;
while (match = rx.exec(str)) callback(match[0]);
}
Then use that words iterator function from the longestWord function, which makes this algorithm extremely trivial now:
function longestWord(sen) {
var longestWord = '';
forEachWordsIn(sen, function (word) {
if (word.length > longestWord.length) longestWord = word;
});
return longestWord;
}
Note: I renamed LongestWord to longestWord because making functions start with captital letters is a well known standard to identify constructor functions.

Having trouble solving this JavaScript coding challenge from coderbyte

I'm attempting to solve the following problem from coderbyte.com:
Using the JavaScript language, have the function SimpleSymbols(str) take the str parameter being passed and determine if it is an acceptable sequence by either returning the string true or false. The str parameter will be composed of + and = symbols with several letters between them (ie. ++d+===+c++==a) and for the string to be true each letter must be surrounded by a + symbol. So the string to the left would be false. The string will not be empty and will have at least one letter.
The following is my attempt:
function SimpleSymbols(str) {
// code goes here
var abc = 'abcdefghijklmnopqrstuvwxyz';
for (var i = 0; i < str.length; i++) {
if (abc.indexOf(str[i]) !== -1) {
if (str[i-1] + str[i+1] === "++") {
return true;
}
else {
return false;
}
}
}
}
This works for the following cases:
SimpleSymbols("+a+d+"); // true
SimpleSymbols("+ab+d+"); // false
SimpleSymbols("b+d+"); // false
The only case I have found where this doesn't provide the right answer is when there is a trailing letter, for example:
SimpleSymbols("+a+b"); // true
This returns true, when in fact it should return false.
NB: I'm assuming string will be lowercase... I haven't dealt with case sensitivity, but I'd like to get the lowercase version working and then I will make it case independent.
Any ideas on what is wrong with my code?
I interpret this as: There is no letter which is not preceded/followed by a character other than plus (including none):
function SimpleSymbols(str) {
return !/^[a-z]|[^+][a-z]|[a-z][^+]|[a-z]$/i.test(str)
}
You may use a regex:
function SimpleSymbols(str) {
if (/^[a-zA-Z]/.test(str) || /[a-zA-Z]$/.test(str)) {
return false;
}
else if (/[^+][a-zA-Z]/.test(str) || /[a-zA-Z][^+]/.test(str)) {
return false;
}
else {
return true;
}
}
or
function SimpleSymbols(str) {
var arr = str.toLowerCase().split("");
for (var i = 0; i < arr.length; i++) {
if (arr[i] >= "a" && arr[i] <= "z") {
if (i === 0 || i === arr.length) {
return false;
}
if (arr[i-1] !== "+" || arr[i+1] !== "+") {
return false;
}
}
}
return true;
}
This returns 'true' on the first successful letter surrounded by + symbols, it doesn't continue checking thru to the end.
I also wonder whether string indices would be out-of-bounds [i-1], [i+1] on the first/last character? It appears not, but I can't find a language ref.
Better:
function SimpleSymbols(str) {
var abc = 'abcdefghijklmnopqrstuvwxyz';
for (var i = 0; i < str.length; i++) {
if (abc.indexOf(str[i]) !== -1) {
if (str[i-1] + str[i+1] != "++") {
return false;
}
}
}
return true;
}
There are also probably performance improvements that could be made (checking bounding characters by AND rather than by string addition), and you could also do it by a regex.
By regex:
if (str.search( /[^+][a-z]/) >= 0) // will match letters with no + beforehand.
return false;
if (str.search( /[a-z][^+]/) >= 0) // will match letters with no + afterward.
return false;
return true;
I believe this is a perfect regex case
Check the regex ^[^a-z]*(\++[a-z]\++[a-z]?)*[^a-z]*$ explained in here
Use it in javascript like this:
function SimpleSymbols(str) {
return !/^[^a-z]*(\++[a-z]\++[a-z]?)*[^a-z]*$/i.test(str);
}
export const simpleSymbols = (str) => {
const arr = str.split('')
let k = []
arr.forEach(element => {
if((/[a-zA-Z]/).test(element)){
if(arr[arr.indexOf(element)-1]==="+" && arr[arr.indexOf(element)+1]==="+"){
k.push(1)
}else{
k.push(0)
}
}
});
if(k.includes(0)){
return false
}else{
return true
}
}

Javascript word-count for any given DOM element

I'm wondering if there's a way to count the words inside a div for example. Say we have a div like so:
<div id="content">
hello how are you?
</div>
Then have the JS function return an integer of 4.
Is this possible? I have done this with form elements but can't seem to do it for non-form ones.
Any ideas?
g
If you know that the DIV is only going to have text in it, you can KISS:
var count = document.getElementById('content').innerHTML.split(' ').length;
If the div can have HTML tags in it, you're going to have to traverse its children looking for text nodes:
function get_text(el) {
ret = "";
var length = el.childNodes.length;
for(var i = 0; i < length; i++) {
var node = el.childNodes[i];
if(node.nodeType != 8) {
ret += node.nodeType != 1 ? node.nodeValue : get_text(node);
}
}
return ret;
}
var words = get_text(document.getElementById('content'));
var count = words.split(' ').length;
This is the same logic that the jQuery library uses to achieve the effect of its text() function. jQuery is a pretty awesome library that in this case is not necessary. However, if you find yourself doing a lot of DOM manipulation or AJAX then you might want to check it out.
EDIT:
As noted by Gumbo in the comments, the way we are splitting the strings above would count two consecutive spaces as a word. If you expect that sort of thing (and even if you don't) it's probably best to avoid it by splitting on a regular expression instead of on a simple space character. Keeping that in mind, instead of doing the above split, you should do something like this:
var count = words.split(/\s+/).length;
The only difference being on what we're passing to the split function.
Paolo Bergantino's second solution is incorrect for empty strings or strings that begin or end with whitespaces. Here's the fix:
var count = !s ? 0 : (s.split(/^\s+$/).length === 2 ? 0 : 2 +
s.split(/\s+/).length - s.split(/^\s+/).length - s.split(/\s+$/).length);
Explanation: If the string is empty, there are zero words; If the string has only whitespaces, there are zero words; Else, count the number of whitespace groups without the ones from the beginning and the end of the string.
string_var.match(/[^\s]+/g).length
seems like it's a better method than
string_var.split(/\s+/).length
At least it won't count "word " as 2 words -- ['word'] rather than ['word', '']. And it doesn't really require any funny add-on logic.
Or just use Countable.js to do the hard job ;)
document.deepText= function(hoo){
var A= [];
if(hoo){
hoo= hoo.firstChild;
while(hoo!= null){
if(hoo.nodeType== 3){
A[A.length]= hoo.data;
}
else A= A.concat(arguments.callee(hoo));
hoo= hoo.nextSibling;
}
}
return A;
}
I'd be fairly strict about what a word is-
function countwords(hoo){
var text= document.deepText(hoo).join(' ');
return text.match(/[A-Za-z\'\-]+/g).length;
}
alert(countwords(document.body))
Or you can do this:
function CountWords (this_field, show_word_count, show_char_count) {
if (show_word_count == null) {
show_word_count = true;
}
if (show_char_count == null) {
show_char_count = false;
}
var char_count = this_field.value.length;
var fullStr = this_field.value + " ";
var initial_whitespace_rExp = /^[^A-Za-z0-9]+/gi;
var left_trimmedStr = fullStr.replace(initial_whitespace_rExp, "");
var non_alphanumerics_rExp = rExp = /[^A-Za-z0-9]+/gi;
var cleanedStr = left_trimmedStr.replace(non_alphanumerics_rExp, " ");
var splitString = cleanedStr.split(" ");
var word_count = splitString.length -1;
if (fullStr.length <2) {
word_count = 0;
}
if (word_count == 1) {
wordOrWords = " word";
} else {
wordOrWords = " words";
}
if (char_count == 1) {
charOrChars = " character";
} else {
charOrChars = " characters";
}
if (show_word_count & show_char_count) {
alert ("Word Count:\n" + " " + word_count + wordOrWords + "\n" + " " + char_count + charOrChars);
} else {
if (show_word_count) {
alert ("Word Count: " + word_count + wordOrWords);
} else {
if (show_char_count) {
alert ("Character Count: " + char_count + charOrChars);
}
}
}
return word_count;
}
The get_text function in Paolo Bergantino's answer didn't work properly for me when two child nodes have no space between them. eg <h1>heading</h1><p>paragraph</p> would be returned as headingparagraph (notice lack of space between the words). So prepending a space to the nodeValue fixes this. But it introduces a space at the front of the text but I found a word count function that trims it off (plus it uses several regexps to ensure it counts words only). Word count and edited get_text functions below:
function get_text(el) {
ret = "";
var length = el.childNodes.length;
for(var i = 0; i < length; i++) {
var node = el.childNodes[i];
if(node.nodeType != 8) {
ret += node.nodeType != 1 ? ' '+node.nodeValue : get_text(node);
}
}
return ret;
}
function wordCount(fullStr) {
if (fullStr.length == 0) {
return 0;
} else {
fullStr = fullStr.replace(/\r+/g, " ");
fullStr = fullStr.replace(/\n+/g, " ");
fullStr = fullStr.replace(/[^A-Za-z0-9 ]+/gi, "");
fullStr = fullStr.replace(/^\s+/, "");
fullStr = fullStr.replace(/\s+$/, "");
fullStr = fullStr.replace(/\s+/gi, " ");
var splitString = fullStr.split(" ");
return splitString.length;
}
}
EDIT
kennebec's word counter is really good. But the one I've found includes a number as a word which is what I needed. Still, that's easy to add to kennebec's. But kennebec's text retrieval function will have the same problem.
This should account for preceding & trailing whitespaces
const wordCount = document.querySelector('#content').innerText.trim().split(/\s+/).length;
string_var.match(/[^\s]+/g).length - 1;

Categories