This tutorial shows how to create a real-time text counter that tracks characters, words, sentences, paragraphs, spaces, emojis, and unknown characters. The counter uses LocalStorage to save the text so that it is preserved even if the page is refreshed. This article explains each function in detail and covers security considerations, advantages, and disadvantages.
1. HTML Setup
The first step is to set up a simple HTML structure. This HTML includes a textarea for input and several elements to display the counts.
The following code shows the HTML setup:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Advanced Text Counter</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
}
textarea {
width: 100%;
max-width: 600px;
height: 150px;
font-size: 16px;
}
p {
font-size: 18px;
margin: 5px 0;
}
</style>
</head>
<body>
<h1>Advanced JavaScript Character Counter</h1>
<textarea id="textArea" placeholder="Type something..."></textarea>
<p>Characters: <span id="charCount">0</span></p>
<p>Words: <span id="wordCount">0</span></p>
<p>Sentences: <span id="sentenceCount">0</span></p>
<p>Paragraphs: <span id="paragraphCount">0</span></p>
<p>Spaces: <span id="spaceCount">0</span></p>
<p>Emojis: <span id="emojiCount">0</span></p>
<p>Unknown Characters: <span id="unknownCharCount">0</span></p>
<script src="script.js"></script>
</body>
</html>
2. JavaScript Functions Explained
The JavaScript code handles input changes, counts different text properties, and saves the text to LocalStorage. Each function is explained below.
A. Counting Characters
This function returns the total number of characters in the text (including spaces and punctuation).
function countCharacters(text) {
return text.length;
}
B. Counting Words
This function splits the text by whitespace after trimming and filters out empty entries.
function countWords(text) {
return text.trim().split(/\s+/).filter(function(word) {
return word !== "";
}).length;
}
C. Counting Sentences
This function splits the text using sentence-ending punctuation (periods, question marks, exclamation points) and filters out empty results.
function countSentences(text) {
return text.split(/[.!?]+/).filter(function(sentence) {
return sentence.trim() !== "";
}).length;
}
D. Counting Paragraphs
This function splits the text by newline characters and filters out empty paragraphs.
function countParagraphs(text) {
return text.split(/\n+/).filter(function(paragraph) {
return paragraph.trim() !== "";
}).length;
}
E. Counting Spaces
This function uses a regular expression to count all whitespace characters (spaces, tabs, etc.).
function countSpaces(text) {
return (text.match(/\s/g) || []).length;
}
F. Counting Emojis
This function uses Unicode property escapes to match emoji characters from the extended pictographic set.
function countEmojis(text) {
var emojiRegex = /[\p{Extended_Pictographic}]/gu;
return (text.match(emojiRegex) || []).length;
}
G. Counting Unknown Characters
This function counts characters that do not match typical letters, numbers, punctuation, or whitespace.
function countUnknownCharacters(text) {
var knownCharRegex = /[\p{L}\p{N}\p{P}\p{Z}]/gu;
return text.replace(knownCharRegex, "").length;
}
H. Saving and Loading Data with LocalStorage
These functions ensure that text is saved in the browser so it is not lost on page refresh.
// Save the current text in LocalStorage
function saveText() {
localStorage.setItem("savedText", document.getElementById("textArea").value);
}
// Load the saved text from LocalStorage
function loadText() {
var storedText = localStorage.getItem("savedText");
if (storedText) {
document.getElementById("textArea").value = storedText;
}
}
I. Updating Counters in Real-time
This function updates all counts based on the textarea's value and saves the text.
function updateCounters() {
var text = document.getElementById("textArea").value;
document.getElementById("charCount").textContent = countCharacters(text);
document.getElementById("wordCount").textContent = countWords(text);
document.getElementById("sentenceCount").textContent = countSentences(text);
document.getElementById("paragraphCount").textContent = countParagraphs(text);
document.getElementById("spaceCount").textContent = countSpaces(text);
document.getElementById("emojiCount").textContent = countEmojis(text);
document.getElementById("unknownCharCount").textContent = countUnknownCharacters(text);
saveText();
}
J. Event Listeners
These listeners call updateCounters when the user types and when the page loads to load saved text.
document.getElementById("textArea").addEventListener("input", updateCounters);
window.addEventListener("load", function() {
loadText();
updateCounters();
});
3. Advantages and Disadvantages
Advantages
- Real-time updates provide immediate feedback.
- Works offline without needing an internet connection.
- Supports multiple languages and handles emojis.
- Customizable and extendable with additional features.
- LocalStorage preserves user data on refresh.
Disadvantages
- Older browsers may not support advanced Unicode regex features.
- Limited to client-side processing and storage.
- Extremely large texts may cause performance issues.
- Potential security risks if user input is not properly sanitized.
4. Security Considerations
While the counter is lightweight and self-contained, consider these security issues:
- Cross-Site Scripting risks if user input is rendered unsafely.
- Denial-of-Service risks from processing excessively large inputs.
- Privacy concerns if sensitive data is stored without proper caution.
- Unicode spoofing by combining characters to impersonate trusted strings.
5. Final Code
The complete code, including HTML and JavaScript, is shown below:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Advanced Text Counter</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
}
textarea {
width: 100%;
max-width: 600px;
height: 150px;
font-size: 16px;
}
p {
font-size: 18px;
margin: 5px 0;
}
</style>
</head>
<body>
<h1>Advanced JavaScript Character Counter</h1>
<textarea id="textArea" placeholder="Type something..."></textarea>
<p>Characters: <span id="charCount">0</span></p>
<p>Words: <span id="wordCount">0</span></p>
<p>Sentences: <span id="sentenceCount">0</span></p>
<p>Paragraphs: <span id="paragraphCount">0</span></p>
<p>Spaces: <span id="spaceCount">0</span></p>
<p>Emojis: <span id="emojiCount">0</span></p>
<p>Unknown Characters: <span id="unknownCharCount">0</span></p>
<script>
function countCharacters(text) {
return text.length;
}
function countWords(text) {
return text.trim().split(/\s+/).filter(function(word) { return word !== ""; }).length;
}
function countSentences(text) {
return text.split(/[.!?]+/).filter(function(sentence) { return sentence.trim() !== ""; }).length;
}
function countParagraphs(text) {
return text.split(/\n+/).filter(function(paragraph) { return paragraph.trim() !== ""; }).length;
}
function countSpaces(text) {
return (text.match(/\s/g) || []).length;
}
function countEmojis(text) {
var emojiRegex = /[\p{Extended_Pictographic}]/gu;
return (text.match(emojiRegex) || []).length;
}
function countUnknownCharacters(text) {
var knownCharRegex = /[\p{L}\p{N}\p{P}\p{Z}]/gu;
return text.replace(knownCharRegex, "").length;
}
function saveText() {
localStorage.setItem("savedText", document.getElementById("textArea").value);
}
function loadText() {
var storedText = localStorage.getItem("savedText");
if (storedText) {
document.getElementById("textArea").value = storedText;
}
}
function updateCounters() {
var text = document.getElementById("textArea").value;
document.getElementById("charCount").textContent = countCharacters(text);
document.getElementById("wordCount").textContent = countWords(text);
document.getElementById("sentenceCount").textContent = countSentences(text);
document.getElementById("paragraphCount").textContent = countParagraphs(text);
document.getElementById("spaceCount").textContent = countSpaces(text);
document.getElementById("emojiCount").textContent = countEmojis(text);
document.getElementById("unknownCharCount").textContent = countUnknownCharacters(text);
saveText();
}
document.getElementById("textArea").addEventListener("input", updateCounters);
window.addEventListener("load", function() {
loadText();
updateCounters();
});
</script>
</body>
</html>
6. Demo and Final Thoughts
Click here to See the Demo Preview.
Advantages include real-time updates, offline functionality, multilingual support, and persistent data storage with LocalStorage. Disadvantages include limited support in older browsers, performance concerns with large input, and potential security issues if user input is not sanitized.
Happy coding!
Leave a Reply