Java實(shí)現(xiàn)獲取一段文字中文字符數(shù)量的工具類
1. 項(xiàng)目背景詳細(xì)介紹
隨著互聯(lián)網(wǎng)時(shí)代的到來(lái),各類應(yīng)用中對(duì)于文本的處理日益頻繁,其中往往需要對(duì)不同語(yǔ)言的字符進(jìn)行分析與統(tǒng)計(jì)。在多語(yǔ)言混排的文本中,中文字符、英文字符、數(shù)字、標(biāo)點(diǎn)符號(hào)等并存,而許多業(yè)務(wù)場(chǎng)景需要單獨(dú)統(tǒng)計(jì)中文字符的數(shù)量。典型場(chǎng)景包括:
- 內(nèi)容質(zhì)量檢測(cè):在新聞、論壇、博客等編輯系統(tǒng)中,限制或提示中文字符數(shù),以保證文章長(zhǎng)度和可讀性。
- 短信計(jì)費(fèi):國(guó)內(nèi)短信按中文與英文字符分段計(jì)費(fèi),需精確統(tǒng)計(jì)其中的中文字符數(shù)量。
- 排版排查:在排版生成時(shí),統(tǒng)計(jì)中文字符占比,以決定字體大小、行間距、版式分割點(diǎn)等。
- 數(shù)據(jù)分析:在大數(shù)據(jù)文本分析中,需區(qū)分中英文數(shù)據(jù)分布,評(píng)估中文信息量等。
因此,本項(xiàng)目旨在設(shè)計(jì)并實(shí)現(xiàn)一個(gè)通用的 Java 工具類,能夠高效、準(zhǔn)確地統(tǒng)計(jì)一段文本中 中文字符 的數(shù)量。工具類應(yīng)兼容各類 Java 環(huán)境,接口簡(jiǎn)單易用,并提供豐富的單元測(cè)試與文檔說(shuō)明,方便集成到各種 Java 應(yīng)用中。
2. 項(xiàng)目需求詳細(xì)介紹
為確保工具類功能完整、健壯易用,需明確以下 功能需求 與 非功能需求。
2.1 功能需求
中文字符統(tǒng)計(jì)
- 接口方法
int countChinese(String text):統(tǒng)計(jì)輸入字符串text中的中文字符個(gè)數(shù); - 要求僅統(tǒng)計(jì) Unicode 范圍內(nèi)的漢字字符,不含標(biāo)點(diǎn)、符號(hào)、日文漢字;
支持批量處理
- 支持對(duì)包含大量文本(如幾萬(wàn)字或幾百萬(wàn)字)的統(tǒng)計(jì),要求性能盡可能高;
- 可在多線程場(chǎng)景下并發(fā)調(diào)用,無(wú)狀態(tài)或線程安全;
可擴(kuò)展正則
- 默認(rèn)使用正則
[\u4E00-\u9FFF],兼容常用漢字; - 支持可選參數(shù)自定義需要統(tǒng)計(jì)的 Unicode 區(qū)間或正則;
空值與異常處理
- 當(dāng)
text為null或空字符串時(shí),返回0; - 對(duì)非法正則或參數(shù),應(yīng)拋出
IllegalArgumentException;
2.2 非功能需求
接口設(shè)計(jì)
- 提供靜態(tài)工具方法
ChineseCounter.countChinese(text); - 提供面向?qū)嵗目膳渲冒?
new ChineseCounter(pattern).count(text);
性能
- 對(duì)于大文本,應(yīng)避免重復(fù)編譯正則,可復(fù)用
Pattern; - 支持流式處理(如
Reader輸入),減少內(nèi)存占用;
線程安全
- 靜態(tài)方法內(nèi)部使用線程安全的數(shù)據(jù)結(jié)構(gòu)或局部變量;
- 可在多線程環(huán)境中安全調(diào)用,無(wú)需外部同步;
測(cè)試覆蓋
使用 JUnit 編寫單元測(cè)試,覆蓋正常和邊界場(chǎng)景:中英混排、Emoji、全空、全中文、大文本等;
文檔與注釋
- 按照 Javadoc 規(guī)范編寫類注釋、方法注釋與參數(shù)/異常說(shuō)明;
- 提供使用示例和常見(jiàn)問(wèn)題解答說(shuō)明。
3. 相關(guān)技術(shù)詳細(xì)介紹
實(shí)現(xiàn)上述功能,需要掌握或了解以下 Java 核心技術(shù)點(diǎn):
3.1 正則表達(dá)式(java.util.regex)
Pattern 與 Matcher
Pattern.compile(regex):將正則編譯為模式對(duì)象;Matcher matcher = pattern.matcher(text):對(duì)目標(biāo)文本進(jìn)行匹配;matcher.find()與matcher.group():定位并提取匹配子串;
Unicode 區(qū)間
- 常用漢字范圍:
\u4E00-\u9FFF; - 擴(kuò)展?jié)h字:
\u3400-\u4DBF(CJK 擴(kuò)展 A 區(qū))、\u20000-\u2A6DF(擴(kuò)展 B 區(qū),需要 Surrogate Pair); - 配合正則后綴
+或{n}控制匹配;
3.2 字符與碼點(diǎn)
char 與 int codePoint
- Java
char為 UTF-16 單元,BMP 區(qū)漢字可直接用char匹配; - 對(duì)于擴(kuò)展字符(如擴(kuò)展 B 區(qū)),需要使用
text.codePoints()流式處理;
流式 API(Java 8+)
text.chars()或text.codePoints()可以逐個(gè)讀取字符/碼點(diǎn);- 結(jié)合
filter與count,可實(shí)現(xiàn)函數(shù)式統(tǒng)計(jì)。
3.3 IO 與大文本處理
Reader 與 BufferedReader
對(duì)于大文本,可支持 count(Reader),逐行或逐塊讀取并統(tǒng)計(jì),降低內(nèi)存壓力;
并發(fā)與分段統(tǒng)計(jì)
可將大文本分為多段,在多個(gè)線程中并發(fā)處理,最后匯總結(jié)果;
3.4 單元測(cè)試
JUnit 5
- 使用
@Test注解編寫用例; - 使用
@ParameterizedTest和@ValueSource提供多場(chǎng)景; - 驗(yàn)證正確性與異常拋出。
4. 實(shí)現(xiàn)思路詳細(xì)介紹
根據(jù)需求與技術(shù)選型,設(shè)定以下設(shè)計(jì)思路:
1.工具類與實(shí)例類分離
public final class ChineseCounter:
- 私有構(gòu)造方法,防止實(shí)例化;
- 公共靜態(tài)方法使用默認(rèn)正則;
public class ChineseCounter.Instance:
接受自定義正則或 Unicode 區(qū)間;
內(nèi)部持有 Pattern 實(shí)例,復(fù)用匹配;
2.靜態(tài)方法實(shí)現(xiàn)
public static int countChinese(String text) {
if (text == null || text.isEmpty()) return 0;
Matcher m = DEFAULT_PATTERN.matcher(text);
int count = 0;
while (m.find()) count++;
return count;
}
流式方法實(shí)現(xiàn)
public static long countByCodePoint(String text) {
if (text == null) return 0;
return text.codePoints()
.filter(cp -> cp >= 0x4E00 && cp <= 0x9FFF)
.count();
}
Reader 版本
public static int countChinese(Reader reader) {
BufferedReader br = new BufferedReader(reader);
String line;
int total = 0;
while ((line = br.readLine()) != null) {
total += countChinese(line);
}
return total;
}
5. 完整實(shí)現(xiàn)代碼
// 文件:ChineseCounter.java
package com.example.textcounter;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 中文字符統(tǒng)計(jì)工具類
* 支持靜態(tài)方法與可配置實(shí)例對(duì)象兩種方式
*/
public final class ChineseCounter {
// 默認(rèn)匹配漢字的正則:包含常用漢字(CJK Unified Ideographs)
private static final Pattern DEFAULT_PATTERN = Pattern.compile("[\\u4E00-\\u9FFF]");
// 私有構(gòu)造,禁止實(shí)例化
private ChineseCounter() {}
/**
* 靜態(tài)方法:統(tǒng)計(jì)字符串中的中文字符數(shù)量(使用默認(rèn)范圍)
* @param text 輸入文本
* @return 中文字符個(gè)數(shù)
*/
public static int countChinese(String text) {
if (text == null || text.isEmpty()) return 0;
Matcher matcher = DEFAULT_PATTERN.matcher(text);
int count = 0;
while (matcher.find()) {
count++;
}
return count;
}
/**
* 靜態(tài)方法:基于字符碼點(diǎn)方式統(tǒng)計(jì)中文數(shù)量(推薦:性能更優(yōu))
* @param text 輸入文本
* @return 中文字符個(gè)數(shù)
*/
public static long countChineseByCodePoint(String text) {
if (text == null) return 0;
return text.codePoints()
.filter(cp -> (cp >= 0x4E00 && cp <= 0x9FFF)) // 可擴(kuò)展至其他 Unicode 區(qū)
.count();
}
/**
* 靜態(tài)方法:按行讀取字符流并統(tǒng)計(jì)中文數(shù)量(適合大文本)
* @param reader 字符流 Reader
* @return 中文字符個(gè)數(shù)
* @throws IOException 讀取異常
*/
public static int countChinese(Reader reader) throws IOException {
if (reader == null) return 0;
BufferedReader br = new BufferedReader(reader);
String line;
int total = 0;
while ((line = br.readLine()) != null) {
total += countChinese(line);
}
return total;
}
/**
* 可配置實(shí)例類(支持自定義正則)
*/
public static class Instance {
private final Pattern pattern;
/**
* 使用正則表達(dá)式創(chuàng)建統(tǒng)計(jì)實(shí)例
* @param regex 自定義正則(必須非空)
*/
public Instance(String regex) {
if (regex == null || regex.isEmpty()) {
throw new IllegalArgumentException("正則表達(dá)式不能為空");
}
this.pattern = Pattern.compile(regex);
}
/**
* 使用 Unicode 范圍創(chuàng)建統(tǒng)計(jì)實(shí)例
* @param start 起始碼點(diǎn)(如 0x4E00)
* @param end 結(jié)束碼點(diǎn)(如 0x9FFF)
*/
public Instance(int start, int end) {
if (start > end) {
throw new IllegalArgumentException("起始碼點(diǎn)不能大于結(jié)束碼點(diǎn)");
}
String regex = String.format("[%s-%s]",
new String(Character.toChars(start)),
new String(Character.toChars(end)));
this.pattern = Pattern.compile(regex);
}
/**
* 使用該實(shí)例統(tǒng)計(jì)字符串中的匹配字符數(shù)量
* @param text 輸入文本
* @return 匹配字符數(shù)量
*/
public int count(String text) {
if (text == null || text.isEmpty()) return 0;
Matcher matcher = pattern.matcher(text);
int count = 0;
while (matcher.find()) {
count++;
}
return count;
}
}
}
// 文件:ChineseCounterTest.java
package com.example.textcounter;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
/**
* 中文字符統(tǒng)計(jì)測(cè)試類
*/
public class ChineseCounterTest {
@Test
public void testNullAndEmpty() {
assertEquals(0, ChineseCounter.countChinese(null));
assertEquals(0, ChineseCounter.countChinese(""));
}
@Test
public void testMixedContent() {
String text = "你好,world!123";
assertEquals(2, ChineseCounter.countChinese(text));
}
@Test
public void testOnlyChinese() {
String text = "這是純中文";
assertEquals(5, ChineseCounter.countChinese(text));
}
@Test
public void testCodePointMethod() {
String text = "ABC和中文組合??";
assertEquals(3, ChineseCounter.countChineseByCodePoint(text));
}
@Test
public void testCustomInstanceRegex() {
ChineseCounter.Instance custom = new ChineseCounter.Instance("[\\u4E00-\\u9FFF]");
assertEquals(4, custom.count("中英文混排測(cè)試"));
}
@Test
public void testUnicodeRange() {
ChineseCounter.Instance range = new ChineseCounter.Instance(0x4E00, 0x9FFF);
assertEquals(2, range.count("Hello中國(guó)"));
}
@Test
public void testInvalidRegex() {
assertThrows(IllegalArgumentException.class, () -> new ChineseCounter.Instance(""));
}
@Test
public void testInvalidUnicodeRange() {
assertThrows(IllegalArgumentException.class, () -> new ChineseCounter.Instance(0x9FFF, 0x4E00));
}
}
6. 代碼詳細(xì)解讀(方法作用說(shuō)明)
countChinese(String text):使用正則[\\u4E00-\\u9FFF]統(tǒng)計(jì)字符串中中文字符數(shù)量;countChineseByCodePoint(String text):使用 Unicode 碼點(diǎn)判斷是否屬于常用漢字區(qū)間,提高性能;countChinese(Reader reader):適用于大文本,按行讀取字符流并統(tǒng)計(jì);ChineseCounter.Instance(String regex):允許用戶自定義正則表達(dá)式作為匹配規(guī)則;ChineseCounter.Instance(int start, int end):允許用戶以 Unicode 范圍構(gòu)造匹配規(guī)則;count(String text)(實(shí)例方法):對(duì)輸入文本應(yīng)用實(shí)例配置的規(guī)則進(jìn)行統(tǒng)計(jì);- 測(cè)試類
ChineseCounterTest:使用 JUnit 驗(yàn)證工具類對(duì)各種文本場(chǎng)景的處理是否正確。
7. 項(xiàng)目詳細(xì)總結(jié)
本項(xiàng)目實(shí)現(xiàn)了一個(gè)輕量級(jí)、高性能、可復(fù)用的中文字符統(tǒng)計(jì)工具。它通過(guò) Java 正則表達(dá)式、字符碼點(diǎn)等核心技術(shù),準(zhǔn)確識(shí)別一段文字中的常用中文字符數(shù)量,并提供了靈活的 API 接口:
- 靜態(tài)方法簡(jiǎn)單易用,滿足大多數(shù)場(chǎng)景;
- 實(shí)例方法可擴(kuò)展性強(qiáng),支持定制匹配范圍;
- 支持大文本與字符流處理,避免內(nèi)存問(wèn)題;
- 完整的單元測(cè)試覆蓋,確保準(zhǔn)確性與穩(wěn)定性;
- 零依賴,適用于所有 Java 應(yīng)用(桌面、后端、移動(dòng))。
本工具可廣泛應(yīng)用于文本分析、內(nèi)容審核、界面字符計(jì)數(shù)等需求場(chǎng)景中,也可作為其他 NLP 工具的子模塊進(jìn)行集成。
8. 項(xiàng)目常見(jiàn)問(wèn)題及解答
Q1: 為什么正則只用了 [\\u4E00-\\u9FFF]?
這是最常用的 CJK 漢字區(qū),基本能覆蓋日常中文應(yīng)用。若需要擴(kuò)展到 CJK 擴(kuò)展 A/B/C 區(qū),可在 countChineseByCodePoint() 中修改范圍。
Q2: 是否支持統(tǒng)計(jì)標(biāo)點(diǎn)符號(hào)、日文、韓文?
默認(rèn)不支持。如果需要,可通過(guò)實(shí)例化構(gòu)造器傳入包含這些字符的正則(如 [\u4E00-\u9FFF\u3000-\u303F])。
Q3: 對(duì) emoji 有影響嗎?
沒(méi)有影響,emoji 屬于 Unicode 較高區(qū)段,不會(huì)被默認(rèn)正則匹配。
Q4: 處理超大文本安全嗎?
是。通過(guò) Reader 輸入并逐行處理的版本可以用于幾 MB 甚至 GB 級(jí)別的文本處理。
Q5: 線程安全嗎?
工具類無(wú)狀態(tài);實(shí)例類僅讀共享 Pattern,是線程安全的;可放心在并發(fā)環(huán)境中使用。
9. 擴(kuò)展方向與性能優(yōu)化
1.多 Unicode 范圍支持
- 擴(kuò)展匹配范圍至 CJK 擴(kuò)展 A(0x3400-0x4DBF)、擴(kuò)展 B(0x20000-0x2A6DF)等;
- 支持中文標(biāo)點(diǎn)(0x3000-0x303F)等。
2.字符頻率統(tǒng)計(jì)
- 返回 Map<Character, Integer> 統(tǒng)計(jì)中文字符的使用頻率;
- 用于詞云生成、關(guān)鍵字提取等。
3.多線程加速
將長(zhǎng)文本切片后在并行流中統(tǒng)計(jì),進(jìn)一步提升性能;
4.使用 Re2J 替代 JDK 正則引擎
對(duì)正則匹配密集場(chǎng)景可提高性能;
5.集成語(yǔ)言識(shí)別與 NLP 模塊
搭配 HanLP、Jieba 分詞庫(kù)進(jìn)一步識(shí)別實(shí)體、語(yǔ)法等。
到此這篇關(guān)于Java實(shí)現(xiàn)獲取一段文字中文字符數(shù)量的工具類的文章就介紹到這了,更多相關(guān)Java獲取文字中文字符數(shù)量?jī)?nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java8 Supplier接口和Consumer接口原理解析
這篇文章主要介紹了Java8 Supplier接口和Consumer接口原理解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04
基于UDP協(xié)議實(shí)現(xiàn)聊天系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了基于UDP協(xié)議實(shí)現(xiàn)聊天系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-04-04
JSON for java快速入門總結(jié)學(xué)習(xí)
這篇文章主要介紹了JSON for java入門總結(jié)學(xué)習(xí),有需要的可以了解一下。2016-11-11
IDEA利用jclasslib 修改class文件的實(shí)現(xiàn)
這篇文章主要介紹了IDEA利用jclasslib 修改class文件的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02
Mybatis-Plus實(shí)現(xiàn)用戶ID自增出現(xiàn)的問(wèn)題解決
項(xiàng)目基于 SpringBoot + MybatisPlus 3.5.2 使用數(shù)據(jù)庫(kù)自增ID時(shí), 出現(xiàn)重復(fù)鍵的問(wèn)題,本文就來(lái)介紹一下解決方法,感興趣的可以了解一下2023-09-09
BeanUtils.copyProperties()所有的空值不復(fù)制問(wèn)題
這篇文章主要介紹了BeanUtils.copyProperties()所有的空值不復(fù)制問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06
Spring?Boot集成Redisson實(shí)現(xiàn)延遲隊(duì)列
本文詳細(xì)介紹了電商支付場(chǎng)景中利用Redisson的RDelayedQueue實(shí)現(xiàn)訂單的延遲關(guān)閉功能,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2025-08-08

