UNPKG

gmx-word-counter

Version:

Fast, GMX-V compliant word and character counter. Can count both logographic and non-logographic languages correctly. Also supports generic counting for cases when language is unknown.

74 lines 2.79 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.countCharacters = countCharacters; const punctuationUtils_1 = require("./punctuationUtils"); const UnicodeAlphanumeric = /^[\p{L}\p{M}\p{N}]*$/u; // Does not need caching, as just computing it each time is actually faster function isCpUnicodeAlphanumeric(codePoint) { // Within ASCII the only \p{L} and \p{N} characters are A-Z, a-z and 0-9 if (codePoint < 0x80) { return ((codePoint >= 0x30 && codePoint <= 0x39) || (codePoint >= 0x41 && codePoint <= 0x5a) || (codePoint >= 0x61 && codePoint <= 0x7a)); } return UnicodeAlphanumeric.test(String.fromCodePoint(codePoint)); } // Punctuation characters are excluded from the character count, but hyphens // and apostrophes are included if they appear inside of a word. function isCountedAsPunctuation(cp, isInWord) { return (0, punctuationUtils_1.isPunctuationCp)(cp) && !(isInWord && ((0, punctuationUtils_1.isHyphenCp)(cp) || (0, punctuationUtils_1.isApostropheCp)(cp))); } /** * * @param {string} text - text to count characters in */ function countCharacters(text) { if (!text) { return { whiteSpace: 0, characters: 0, punctuation: 0, }; } const normalizedText = text.normalize('NFC'); let totalCharacters = 0; let whiteSpace = 0; let punctuation = 0; // Previous code point, tracked across iterations so that surrogate pairs // are not misread when indexing backwards by code units let prevCp; for (let i = 0; i < normalizedText.length; i++) { const cp = normalizedText.codePointAt(i); // Check for surrogate pair and increment `i` if found if (cp > 0xffff) { i++; } // GMX TotalCharacterCount excludes whitespace. if ((0, punctuationUtils_1.isWhitespaceCp)(cp)) { whiteSpace++; prevCp = cp; continue; } let isInWord = false; if (prevCp !== undefined && i < normalizedText.length - 1) { // `i` points at the last code unit of the current character, // so `i + 1` is the start of the next one (codePointAt decodes // a full surrogate pair when given its leading code unit) const next = normalizedText.codePointAt(i + 1); isInWord = isCpUnicodeAlphanumeric(prevCp) && isCpUnicodeAlphanumeric(next); } if (isCountedAsPunctuation(cp, isInWord)) { punctuation++; } else { totalCharacters++; } prevCp = cp; } return { characters: totalCharacters, whiteSpace, punctuation, }; } //# sourceMappingURL=characterCounter.js.map