如何在JavaScript中统计中日文内容的词数(排除特殊字符)
问题分析
你的代码核心问题在于对中日文“词”的定义和Microsoft Word不一致:
- 中文没有天然的词边界,你的正则把连续汉字当成单个词,但Word的中文词数统计是基于分词结果(比如“我爱编程”会被拆成“我”“爱”“编程”3个词,而非1个);
- 日文同理,你的正则把平假名、片假名、汉字连缀成一个词,但Word会把助词(は、が)、助动词和实词分开统计,比如“私はプログラマー”会被拆成3个词,而非1个;
- 另外,你的正则没有明确覆盖所有需排除的特殊字符,虽然只匹配目标字符,但混合字符场景下可能存在漏判,但这不是和Word结果差异的核心原因。
修正方案
要贴近Word的统计结果,必须用专业的中日文分词库,而非简单正则。以下是具体实现:
中文分词(使用 segmentit)
// 先安装依赖:npm install segmentit const Segment = require('segmentit'); const segmentit = new Segment(); segmentit.useDefault(); function countChineseWords(text) { // 过滤特殊字符、标点、空白 const cleanedText = text.replace(/[^\p{Script=Han}]/gu, ''); // 执行分词 const segments = segmentit.doSegment(cleanedText); // 返回词数 return segments.length; }
日文分词(使用 kuromoji.js)
// 先安装依赖:npm install kuromoji const kuromoji = require('kuromoji'); async function countJapaneseWords(text) { // 过滤特殊字符、标点、空白 const cleanedText = text.replace(/[^\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Han}ー]/gu, ''); // 加载分词字典(首次运行会下载,后续自动缓存) const tokenizer = await kuromoji.builder({ dicPath: 'node_modules/kuromoji/dict' }).build(); const tokens = tokenizer.tokenize(cleanedText); // 排除残留标点,统计有效词数 return tokens.filter(token => !/^[、。!?]+$/.test(token.surface_form)).length; }
整合后的通用方法
async function countWords(text, locale) { // 统一过滤所有Unicode标点和空白字符 let cleanedText = text.replace(/[\p{Punctuation}\s]/gu, ''); switch(locale) { case 'zh': return countChineseWords(cleanedText); case 'ja': return await countJapaneseWords(cleanedText); default: // 其他语言沿用原单词匹配逻辑 const matches = cleanedText.matchAll(/\b\w+\b/gu); return Array.from(matches).length; } }
关键说明
- 为什么不用正则?:中日文属于无空格分隔的语言,词边界无法通过简单正则定义,必须依赖基于词典、机器学习的分词算法,才能得到和Word对齐的结果;
- Word的统计规则:Word中文词数默认采用“分词+单字补充”逻辑,专业分词库的结果基本和Word一致;日文则基于形态素分析,和Word的统计逻辑匹配;
- 过滤规则:
[\p{Punctuation}\s]正则可覆盖所有Unicode标点和空白字符,确保彻底排除非目标内容。
内容的提问来源于stack exchange,提问作者Sherlock
相关产品推荐
相关产品推荐

