I am very new to JavaScript, and I'm trying to figure out how to count how many times a single letter appears in a word. For example, how many times does 'p' appear in 'apple'
Here is what I have written so far but am having trouble figuring out where am I going wrong.
var letterInWord = function (letter, word) {
var letter = 0;
var word = 0;
for (var i = 0; i < letter.charAt; i+= 1) {
if (letter.charAt(i) === " " = true) {
letter++;
console.log('The letter `letter` occurs in `word` 1 time.');
}
}
return letter;
};
You've got a number of problems:
You're reusing parameter names as local variable names. Use different identifiers to track each bit of information in your function.
letter.charAt is undefined, if letter is a number, and is a function if letter is a string. Either way, i < letter.charAt makes no sense.
If you're searching for letter in word why do you want to look at letter.charAt(i)? You probably want word.charAt(i).
" " = true makes no sense at all.
Perhaps you meant something like this?
var letterInWord = function (letter, word) {
var count = 0;
for (var i = 0; i < word.length; i++) {
if (word.charAt(i) === letter) {
count++;
}
}
return count;
};
'apple'.match(/p/g).length // outputs 2
in other words:
var letterInWord = function (letter, word) {
return (word.match( new RegExp(letter, 'g') ) || []).length;
};
FIDDLE
Here's a smaller function that also works with characters like $ or * (and since it's calling length on a string, there's no need to use || [])
'apple'.replace(/[^p]/g,'').length // outputs 2
function charcount(c, str) {
return str.replace(new RegExp('[^'+c+']','g'),'').length
}
console.log = function(x) { document.write(x + "<br />"); };
console.log( "'*' in '4*5*6' = " + charcount('*', '4*5*6') ) // outputs 2
console.log( "'p' in 'pineapples' = " + charcount('p', 'pineapples') )// outputs 3
Related
I created a function that given any string will return the string with the first and last letter of each word capitalized. So far it works in some words, not on others, can someone help me figure out why?
function Capitalize(str) {
var spl = str.split(" ");
var words = [];
for (let i = 0; i < spl.length; i++) {
//For every word
for (let j = 0; j < spl[i].length; j++) {
//For every letter in each word
var word = spl[i];
var size = spl[i].length;
var firstLetterCapital = word.replace(word[0], word[0].toUpperCase()); //Creates new array
var LastLetterCapital = firstLetterCapital.replace(
word[size - 1],
word[size - 1].toUpperCase()
);
}
words.push(LastLetterCapital);
}
console.log(words.join(" "));
}
Capitalize("hello there");
It works when I type : Capitalize("my name is john smith"), but not with Capitalize("hello there")
I know it's a complete mess and probably a very bad way to do it, but I started programming a month ago so give me a break :)
#symlink has already explained why it is "HellO ThEre" instead of "Hello TherE". He also has given a solution to explicitly target first and last character of the string. I have accomplished not much different than already posted by members, except for .. "may be" a little more explanation.
You can break the entire problem in these four steps.
Get all the words into an array.
Create a function, that takes each word and targets first and last character, changes it and returns the changed word.
Apply a mapping step using the function created above (in step 2) to the entire array of words (obtained in step 1).
Join the transformed array, obtained in step 3, using a blank space as a separator.
I have written two functions that accomplish this task. I am sorry for long name of functions. It helps me keep track of things in a complex program (especially when I am in a hurry!).
Step 2 function
function Capitalize_FirstAndLast_One_Word(word){
// Split the string in array for easy access/manipulation by indexing
Split_String = word.split("")
// Target the first word
Split_String[0] = Split_String[0].toUpperCase();
// Target the last word
Split_String[Split_String.length - 1] = Split_String[Split_String.length - 1].toUpperCase();
// Join the array into a single word
Joined_Back = Split_String.join("")
return Joined_Back;
}
Step 1, 3 and 4 function
function Capitalize_Entire_String(str){
Regular_Exp = new RegExp(/\w+/g);
//Below is step 1
MatchedArray = str.match(Regular_Exp);
//Below is step 3
ConvertedArray = MatchedArray.map(Capitalize_FirstAndLast_One_Word);
// Below is step 4
ReturnedString = ConvertedArray.join(" ");
console.log(ReturnedString);
return ReturnedString;
}
Now you have everything. You can use the function like below.
Capitalize_Entire_String("hello there");
Capitalize_Entire_String("hello there this is a test");
Hope this helps. I am sorry if this turned out to be a redundant answer for you.
Reason your code don't work is the use of replace(). replace() will always replace the first character found.
There is absolutely no reason to run a nested loop. You can achieve this using a single loop.
function cap(str){
let spl = str.split(' ');
for(let i = 0; i < spl.length; i++){
let temp = spl[i];
temp = temp[0].toUpperCase() + temp.slice(1)
temp = temp.slice(0,-1) + temp[temp.length - 1].toUpperCase();
spl[i] = temp;
}
return spl.join(' ');
}
console.log(cap("a quick brown fox"))
An easier way is to use map() and template strings.
const cap = str => str
.split(' ')
.map(x => (
x.length === 1 ?
x.toUpperCase() :
`${x[0].toUpperCase()}${x.slice(1,-1)}${x[x.length -1].toUpperCase()}`)
)
.join(' ')
console.log(cap("a quick brown fox"))
To simplify the function, you could split the string into an array, map each word to the desired format, and join it together into a string again.
function Capitalize(str){
return str.split(" ").map((word) => word.charAt(0).toUpperCase() +
(word.length > 2 ? word.substring(1, word.length - 1) : "") +
(word.length > 1 ? word.charAt(word.length - 1).toUpperCase() : "")).join(" ");
}
console.log(Capitalize("i want to capitalize first and last letters"));
Congrats on starting out programming...
You can use this to achieve what you want to do
function capitalizeFirstAndLastLetters (str) {
const words = str.split(" "); // Split the string into words
const modified = [];
for (const word of words) {
if (word.length <= 2) {
modified.push(word.toUpperCase()); // If the word less than 3 characters, the whole word is capitalized
continue;
}
var firstCapital = word[0].toUpperCase(); // word[0] gets the first index of the string (I.e. the first letter of the word)
var lastCapital = word.slice(-1).toUpperCase(); // The slice function slices a portion of the word. slice(-1) gets the last letter
var middlePart = word.slice(1, -1); // slice(1, -1) means start slicing from the second index (I.e. 1) and ignore the last index
modified.push(firstCapital + middlePart + lastCapital);
}
return modified.join(" "); // Join each element in the modified array with a space to get the final string with each words first and last letters capitalized
}
capitalizeFirstAndLastLetters("hello there I am a boy"); // "HellO TherE I AM A BoY"
Try this, it worked for hello world because I guess you want the outcome to be HellO TherE right?:
function capitalize(str) {
var spl = str.split(" ");
var words = [];
for (let i = 0; i < spl.length; i++) {
//For every word
let changedWord = "";
for (let j = 0; j < spl[i].length; j++) {
//For every letter in each word
if(j == 0 || j == spl[i].length - 1) {
changedWord += spl[i][j].toUpperCase();
} else {
changedWord += spl[i][j].toLowerCase();
}
}
words.push(changedWord);
console.log(words);
}
console.log(words.join(" "));
}
capitalize("hello there");
ALSO: Make your functions name start with lowercase letter. Thats just how it is. Starting with uppercase letters usually are Classes. Just a quick tip
Maybe this does what you want, don't want to change much from your code:
function Capitalize(str) {
var spl = str.split(" ");
var words = [];
for (let i = 0; i < spl.length; i++) {
var word = spl[i];
var firstCapital = word[0].toUpperCase(); // get first character after capitalizing
var lastCapital = word.slice(-1).toUpperCase(); // get last character after capitalizing
var midOriginal = word.slice(1, -1);
words.push(firstCapital + midOriginal + lastCapital) // concat 3 parts
}
console.log(words.join(" "));
}
Capitalize("hello there");
This expression:
var LastLetterCapital = firstLetterCapital.replace(
word[size - 1],
word[size - 1].toUpperCase()
);
Is replacing the first occurrence of the character "e" in "There" with an uppercase "E".
Explanation
The replace() function first translates the first param: word[size - 1] to the literal character "e", then replaces the first occurrence of that character with the uppercase "E", resulting in the string "ThEre".
Solution
Use a regular expression as your first parameter instead, to ensure that the last character is targeted, regardless of whether or not that same character shows up anywhere else in the word:
var LastLetterCapital = firstLetterCapital.replace(/.$/, word[size - 1].toUpperCase());
function Capitalize(str) {
var spl = str.split(" ");
var words = [];
for (let i = 0; i < spl.length; i++) {
//For every word
var word = spl[i];
var size = spl[i].length;
for (let j = 0; j < size; j++) {
//For every letter in each word
var firstLetterCapital = word.replace(word[0], word[0].toUpperCase()); //Creates new array
var LastLetterCapital = firstLetterCapital.replace(/.$/, word[size - 1].toUpperCase());
}
words.push(LastLetterCapital);
}
console.log(words.join(" "));
}
Capitalize("hello there");
This should do the trick:
function Capitalize(str) {
return str.replace(/(\b\w|\w\b)/g, l => l.toUpperCase())
}
console.log(Capitalize('i want to be capitalized in a rather strange way'))
Explanation:
In the regular expression /(\b\w|\w\b)/g, \b means "word boundary" and \w means "word character", so (\b\w|\w\b) matches a word boundary followed by a word character OR a word character followed by a word boundary (i.e. the first and last character of words).
The matches of this expression are then passed to the inline function l => l.toUpperCase() (which itself is the second argument to replace) that capitalizes the passed letter.
the string type is immutable, so why don't you try to convert the string to an array like y = word.split('') and do y[0] = word.charAt(0).toUpperCase() and then convert back to string with y.join('')
Good evening, I proceed to explain my situation. I started to get interested in javascript which started to dabble
in this language, I have been doing some online courses which I have encountered the following task, basically I am trying through the condition "for" tell me what is the first repeated letter of a string also adding the funsion ".UpperCase () "which at the beginning worked best, until I entered more characters to the string in this case" x "throwing me as output result" undefined "instead of" the most repeated word is: X "reach the case that the string should Consider all the letters regardless of whether they are lowercase or capital letters, for which I ask for help to understand if ¿there is another way? for this task and thus move forward (Sorry for my bad english)
Well i making this task in JavasScript with Atom Editor
var word = "SQSQSQSSaaaassssxxxY";
var contendor = [];
var calc = [];
var mycalc = 0;
function repeat() {
for (var i = 0; i < word.length; i++) {
if (contendor.includes(word[i])) {} else {
contendor.push(word[i])
calc.push(0)
}
}
for (var p = 0; p < word.length; p++) {
for (var l = 0; l < contendor.length; l++) {
if (word[p].toUpperCase() == word[l]) {
calc[l] = calc[l] + 1
}
}
}
for (var f = 0; f < calc.length; f++) {
if (calc[f] > mycalc) {
mycalc = calc[f]
}
}
}
repeat()
console.log("The first letter repeated its: " + contendor[mycalc])
I expected the output of the String to be: "X"
but the actual output is: "Undefined"
The first error in your script is that you store the wrong value in mycalc:
mycalc = calc[f]
Since you want mycalc to be an index, the above should have been
mycalc = f
Now, you will get a result, but your code is actually going through a lot of effort to find the uppercase character that is repeated most often, not first.
Your comparison should have used toUpperCase on both sides of the comparison, otherwise lower case letters will never match.
To get the character that was repeated most often, you could use a Map (to keep track of the counts like you did in calc):
function mostRepeated(str) {
const map = new Map;
let result;
let maxCount = 0;
for (let ch of str) {
ch = ch.toUpperCase();
let count = (map.get(ch) || 0) + 1;
map.set(ch, count);
if (count > maxCount) {
maxCount = count;
result = ch;
}
}
return result;
}
var word = "MBXAYMZAXmZYxxxxxxxxxxmBxAYMZaXmZY";
console.log(mostRepeated(word));
Note that you should better use function parameters and local variables. Declaring your variables as global is not considered best practice.
You could find the letter that occurs the most number of times in a string by:
first creating a map that relates each unique letter, to the number of times it occurs in the string
converting that map to an array of "key/value" entries, and then sorting those entries by the "count value"
returning the "letter key" that has the largest count
One way to express this in JavaScript would be via the following:
function findMaxLetter(word) {
/* Create a map that relates letters to the number of times that letter occours */
const letterCounts = Array.from(word).reduce((map, letter) => {
return { ...map, [letter] : (map[letter] === undefined ? 0 : map[letter] + 1) }
}, {})
/* Sort letters by the number of times they occour, as determined in letterCounts map */
const letters = Object.entries(letterCounts).sort(([letter0, count0], [letter1, count1]) => {
return count1 - count0
})
.map(([letter]) => letter)
/* Return letter that occoured the most number of times */
return letters[0]
}
console.log("The first letter repeated its: " + findMaxLetter("MBXAYMZAXmZYxxxxxxxxxxmBxAYMZaXmZY"))
I this is solution is most detailed for you
function func( word ){
word = word.toLowerCase();
var i, charCountCache = {};
//store all char counts into an object
for( i = 0; i < word.length; i++){
if( charCountCache[ word[ i ] ] )
charCountCache[ word[ i ] ] = charCountCache[ word[ i ] ] + 1;
else
charCountCache[ word[ i ] ] = 1;
}
//find the max value of char count in cached object
var fieldNames = Object.keys( charCountCache )
, fieldValues = Object.values( charCountCache )
, mostReapeatChar = '', mostReapeatCharCount = 0;
for( i = 0; i < fieldNames.length; i++ ){
if( mostReapeatCharCount < fieldValues[i] ){
mostReapeatCharCount = fieldValues[i];
mostReapeatChar = fieldNames[i];
}
}
console.log('most repeating char: ', mostReapeatChar, ' no of times: ', mostReapeatCharCount )
}
console.log("The first letter repeated its: " + contendor[mycalc])
You tried to print the 14th index of contendor which has only 9 values, that is why your log result was undefined.
You probably wanted to print word[mycalc].
Also if you intended to count x as X, you should have added toUpperCase() to every letter you process/go-through.
This is only a note to the issues in your code, there are better/faster/cleaner solutions to reach the result which i am sure other answers will provide.
my advice would be to create a hashmap such as
letter => [indexLetter1, indexLetter2].
From that hashmap, you could easily find your first repeated letters.
For that string MBXAYMZAXmZYxxxxxxxxxxmBxAYMZaXmZY, hashmap will look like
[
M => [0,5,..],
B => [1, ..],
X => [2, ..],
...
]
now you can find every letter with multiple values in its array, then in those arrays take the one with the lowest value.
If you want to get the index of most repeated letter, you can use Array.from to convert the word into an array. Add a map function to make all letters uppercase.
Get the count of each letter by using reduce and Object.entries
Use indexOf to the get the index of the lettet in the array. Please note that indexOf count the letters from 0.
var word = "MBXAYMZAXmZYxxxxxxxxxxmBxAYMZaXmZY";
var letters = Array.from(word, o => o.toUpperCase());
var [highestLetter, highestCount]= Object.entries(letters.reduce((c, v) => (c[v] = (c[v] || 0) + 1, c), {})).reduce((c, v) => c[1] > v[1] ? c : v);
var index = letters.indexOf(highestLetter);
console.log("Most repeated letter:", highestLetter);
console.log("Count:", highestCount);
console.log("First Index:", index);
I'm new in StackOverflow and JavaScript, I'm trying to get the first letter that repeats from a string considering both uppercase and lowercase letters and counting and obtaining results using the for statement. The problem is that the form I used is too long Analyzing the situation reaches such a point that maybe you can only use a "For" statement for this exercise, which I get to iterate, but not with a cleaner and reduced code has me completely blocked, this is the reason why I request help to understand and continue with the understanding and use of this sentence. In this case, the result was tested in a JavaScript script inside a function and 3 "For" sentences obtaining quite positive results, but I can not create it in 1 only For (Sorry for my bad english google translate)
I making in HTML with JavasScript
var letter = "SYAHSVCXCyXSssssssyBxAVMZsXhZV";
var contendor = [];
var calc = [];
var mycalc = 0;
letter = letter.toUpperCase()
console.log(letter)
function repeats(){
for (var i = 0; i < letter.length; i++) {
if (contendor.includes(letter[i])) {
}else{
contendor.push(letter[i])
calc.push(0)
}
}
for (var p = 0; p < letter.length; p++) {
for (var l = 0; l < contendor.length; l++) {
if (letter[p] == contendor[l]) {
calc [l]= calc [l]+1
}
}
}
for (var f = 0; f < calc.length; f++) {
if ( calc[f] > calc[mycalc]) {
mycalc = f
}
}
}
repeats()
console.log("The most repeated letter its: " + contendor[mycalc]);
I Expected: A result with concise code
It would probably be a lot more concise to use a regular expression: match a character, then lookahead for more characters until you can match that first character again:
var letter = "SYAHSVCXCyXSssssssyBxAVMZsXhZV";
const firstRepeatedRegex = /(.)(?=.*\1)/;
console.log(letter.match(firstRepeatedRegex)[1]);
Of course, if you aren't sure whether a given string contains a repeated character, check that the match isn't null before trying to extract the character:
const input = 'abcde';
const firstRepeatedRegex = /(.)(?=.*\1)/;
const match = input.match(firstRepeatedRegex);
if (match) {
console.log(match[0]);
} else {
console.log('No repeated characters');
}
You could also turn the input into an array and use .find to find the first character whose lastIndexOf is not the same as the index of the character being iterated over:
const getFirstRepeatedCharacter = (str) => {
const chars = [...str];
const char = chars.find((char, i) => chars.lastIndexOf(char) !== i);
return char || 'No repeated characters';
};
console.log(getFirstRepeatedCharacter('abcde'));
console.log(getFirstRepeatedCharacter('SYAHSVCXCyXSssssssyBxAVMZsXhZV'));
If what you're actually looking for is the character that occurs most often, case-insensitive, use reduce to transform the string into an object indexed by character, whose values are the number of occurrences of that character, then identify the largest value:
const getMostRepeatedCharacter = (str) => {
const charsByCount = [...str.toUpperCase()].reduce((a, char) => {
a[char] = (a[char] || 0) + 1;
return a;
}, {});
const mostRepeatedEntry = Object.entries(charsByCount).reduce((a, b) => a[1] >= b[1] ? a : b);
return mostRepeatedEntry[0];
};
console.log(getMostRepeatedCharacter('abcde'));
console.log(getMostRepeatedCharacter('SYAHSVCXCyXSssssssyBxAVMZsXhZV'));
If the first repeated character is what you want, you can push it into an array and check if the character already exists
function getFirstRepeating( str ){
chars = []
for ( var i = 0; i < str.length; i++){
var char = str.charAt(i);
if ( chars.includes( char ) ){
return char;
} else {
chars.push( char );
}
}
return -1;
}
This will return the first repeating character if it exists, or will return -1.
Working
function getFirstRepeating( str ){
chars = []
for ( var i = 0; i < str.length; i++){
var char = str.charAt(i);
if ( chars.includes( char ) ){
return char;
} else {
chars.push( char );
}
}
return -1;
}
console.log(getFirstRepeating("SYAHSVCXCyXSssssssyBxAVMZsXhZV"))
Have you worked with JavaScript objects yet?
You should look into it.
When you loop through your string
let characters = "hemdhdksksbbd";
let charCount = {};
let max = { count: 0, ch: ""}; // will contain max
// rep letter
//Turn string into an array of letters and for
// each letter create a key in the charcount
// object , set it to 1 (meaning that's the first of
// that letter you've found) and any other time
// you see the letter, increment by 1.
characters.split("").forEach(function(character)
{
if(!charCount[character])
charCount[character] = 1;
else
charCount[character]++;
}
//charCount should now contain letters and
// their counts.
//Get the letters from charCount and find the
// max count
Object.keys(charCount). forEach (function(ch){
if(max.count < charCount[ch])
max = { count: charCount[ch], ch: ch};
}
console.log("most reps is: " , max.ch);
This is a pretty terrible solution. It takes 2 loops (reduce) and doesn't handle ties, but it's short and complicated.
Basically keep turning the results into arrays and use array methods split and reduce to find the answer. The first reduce is wrapped in Object.entries() to turn the object back into an array.
let letter = Object.entries(
"SYAHSVCXCyXSssssssyBxAVMZsXhZV".
toUpperCase().
split('').
reduce((p, c) => {
p[c] = isNaN(++p[c]) ? 1 : p[c];
return p;
}, {})
).
reduce((p, c) => p = c[1] > p[1] ? c : p);
console.log(`The most repeated letter is ${letter[0]}, ${letter[1]} times.`);
I've been dealing with an algorithm which takes a sequence of letters in alphabetic order, and if there is a character missing, it returns that character.
For example: fearNotLetter("abcdfg") would return "e".
My questions are:
What is the logic behind this solution?
Why and how regex is used here?
How does the condition in the for loop work?
function fearNotLetter(str) {
var allChars = '';
var notChars = new RegExp('[^'+str+']','g');
for (var i = 0; allChars[allChars.length-1] !== str[str.length-1] ; i++)
allChars += String.fromCharCode(str[0].charCodeAt(0) + i);
return allChars.match(notChars) ? allChars.match(notChars).join('') : undefined;
}
function fearNotLetter(str) {
var allChars = '';
var notChars = new RegExp('[^'+str+']','g'); //1
for (var i = 0; allChars[allChars.length-1] !== str[str.length-1] ; i++)//2
allChars += String.fromCharCode(str[0].charCodeAt(0) + i);
return allChars.match(notChars) ? allChars.match(notChars).join('') : undefined; //3
}
As the variable name says, it creates a negate of str which means
like !abcdfg
Loop, build the full correct string until the last
character of str, means full letters of the alphabet untill character g => abcdefg
Then it compares with match method of string the full text with the provided text:
dummy way you can think
abcdefg - abcdfg then you get e, if there are multiple characters are missing it concatenates with join method.
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;