Files
MaliangAINovalWriter/AINoval/lib/utils/word_count_analyzer.dart
2025-09-10 00:07:52 +08:00

209 lines
6.1 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'dart:convert';
import 'package:ainoval/utils/logger.dart';
import 'package:ainoval/utils/quill_helper.dart';
/// 字数统计信息
class WordCountStats {
const WordCountStats({
required this.charactersNoSpaces,
required this.charactersWithSpaces,
required this.words,
required this.paragraphs,
required this.readTimeMinutes,
});
final int charactersNoSpaces;
final int charactersWithSpaces;
final int words;
final int paragraphs;
final int readTimeMinutes;
}
/// 字数统计分析器
class WordCountAnalyzer {
static const String _tag = 'WordCountAnalyzer';
static const int _averageReadingWordsPerMinute = 200;
/// 统计字数的方法
///
/// @param content 可能是Delta格式或纯文本的内容
/// @return 内容的字数
static int countWords(String? content) {
if (content == null || content.isEmpty) {
return 0;
}
try {
// 使用QuillHelper工具类解析文本内容
final plainText = QuillHelper.deltaToText(content);
// 计算字数 - 使用Unicode字符计数
return _countUnicodeCharacters(plainText);
} catch (e) {
AppLogger.e(_tag, '解析内容失败,尝试直接计数', e);
// 如果解析失败,尝试直接计数
try {
return _countUnicodeCharacters(content);
} catch (e2) {
AppLogger.e(_tag, '字数统计失败返回0', e2);
return 0; // 完全失败时返回0
}
}
}
/// 统计基本字数信息
///
/// @param delta Quill Delta格式内容
/// @return 包含字数、行数、字符数统计结果的Map
static Map<String, int> getBasicStats(String? delta) {
if (delta == null || delta.isEmpty) {
return {'words': 0, 'lines': 0, 'chars': 0};
}
try {
// 使用QuillHelper工具类解析文本内容
final plainText = QuillHelper.deltaToText(delta);
// 计算字数、行数和字符数
final int wordCount = _countUnicodeCharacters(plainText);
final int lineCount = _countLines(plainText);
final int charCount = plainText.length;
return {
'words': wordCount,
'lines': lineCount,
'chars': charCount,
};
} catch (e) {
AppLogger.e(_tag, '解析内容失败,返回默认值', e);
try {
// 尝试直接对原始内容计数
final int wordCount = _countUnicodeCharacters(delta);
final int lineCount = _countLines(delta);
final int charCount = delta.length;
return {
'words': wordCount,
'lines': lineCount,
'chars': charCount,
};
} catch (e2) {
AppLogger.e(_tag, '基本统计失败,返回零值', e2);
return {'words': 0, 'lines': 0, 'chars': 0};
}
}
}
/// 分析文本并返回详细的字数统计信息
///
/// @param content 可能是Delta格式或纯文本的内容
/// @return 详细的字数统计信息
static WordCountStats analyze(String? content) {
if (content == null || content.isEmpty) {
return const WordCountStats(
charactersNoSpaces: 0,
charactersWithSpaces: 0,
words: 0,
paragraphs: 0,
readTimeMinutes: 0,
);
}
// 提取纯文本
String plainText;
try {
plainText = QuillHelper.deltaToText(content);
} catch (e) {
// 如果解析失败,假设是纯文本
plainText = content;
AppLogger.i(_tag, '内容格式解析失败,使用原始内容: ${e.toString()}');
}
try {
// 计算字符数(不含空格)
final charactersNoSpaces = plainText.replaceAll(RegExp(r'\s'), '').length;
// 计算字符数(含空格)
final charactersWithSpaces = plainText.length;
// 计算字数
final words = _countUnicodeCharacters(plainText);
// 计算段落数
final paragraphs = _countParagraphs(plainText);
// 估算阅读时间假设平均每分钟阅读200个字
final readTimeMinutes = _calculateReadingTime(words);
return WordCountStats(
charactersNoSpaces: charactersNoSpaces,
charactersWithSpaces: charactersWithSpaces,
words: words,
paragraphs: paragraphs,
readTimeMinutes: readTimeMinutes,
);
} catch (e) {
AppLogger.e(_tag, '字数分析失败,返回默认值', e);
return const WordCountStats(
charactersNoSpaces: 0,
charactersWithSpaces: 0,
words: 0,
paragraphs: 0,
readTimeMinutes: 0,
);
}
}
/// 统计Unicode字符数更适合中文等非英语字符
static int _countUnicodeCharacters(String text) {
if (text.isEmpty) return 0;
// 移除所有换行符和额外的空格
final String cleanText = text
.replaceAll('\n', '') // 移除换行符
.replaceAll(RegExp(r'\s+'), ' '); // 连续空格替换为单个空格
// 如果清理后为空返回0
if (cleanText.trim().isEmpty) return 0;
// 返回清理后的字符串长度
return cleanText.length;
}
/// 统计行数
static int _countLines(String text) {
if (text.isEmpty) return 0;
// 计算换行符数量
final lineCount = '\n'.allMatches(text).length;
// 如果文本不以换行符结尾加1
return text.endsWith('\n') ? lineCount : lineCount + 1;
}
/// 统计段落数
static int _countParagraphs(String text) {
if (text.isEmpty) return 0;
// 按连续的换行符分割文本,并计算非空段落数
return text.split(RegExp(r'\n+'))
.where((p) => p.trim().isNotEmpty)
.length;
}
/// 计算阅读时间(分钟)
///
/// 假设平均阅读速度为每分钟200个字
static int _calculateReadingTime(int wordCount) {
if (wordCount <= 0) return 0;
return (wordCount / _averageReadingWordsPerMinute).ceil();
}
/// 计算阅读时间(分钟)
///
/// @param content 内容文本
/// @return 估计的阅读时间(分钟)
static int estimateReadingTime(String content) {
final wordCount = countWords(content);
return _calculateReadingTime(wordCount);
}
}