feat:参照研听的基础工程

This commit is contained in:
jingyun
2026-06-18 15:02:28 +08:00
commit 364fc837b3
367 changed files with 16495 additions and 0 deletions
+53
View File
@@ -0,0 +1,53 @@
/// 中西文混排自动加间隙(W3C clreq §3.2.2)。
///
/// 规范要求:横排时汉字与西文字母/数字之间留约 1/4 em 间隙。CSS 有
/// `text-autospace`Flutter 没有对应能力,因此在文本层插入
/// U+2009 THIN SPACE(约 1/5 em,视觉接近规范建议,且远比全角空格克制)。
///
/// 规则(与 pangu 习惯一致):
/// - 汉字 ↔ 字母/数字 相邻 → 插 thin space(「下降2.2%」→「下降 2.2%」);
/// - 西文 run 末尾的 % ‰ 视作 run 的一部分(「2.2%的降幅」→「2.2% 的降幅」);
/// - 全角标点(,。:等)自带空隙,不加;
/// - markdown 版本额外处理强调/行内码边界(「至**138美元**」→「至 **138美元**」),
/// 并跳过 fenced code block;表格管道符、链接 URL 天然不受影响。
library;
const String _thin = '\u2009'; // THIN SPACE
// CJK 统一表意文字(基本区 + 扩展 A + 兼容区)
const String _han = r'㐀-䶿一-鿿豈-﫿';
// 西文边界字符(字母/数字);西文侧在右边界额外允许 % ‰ 收尾
const String _west = r'A-Za-z0-9';
final RegExp _hanWest = RegExp('([$_han])([$_west])');
final RegExp _westHan = RegExp('([$_west%‰])([$_han])');
// 强调/行内码标记夹在边界中间:汉**西 / 西**汉
final RegExp _hanMarkWest = RegExp('([$_han])(\\*{1,3}|`)([$_west])');
final RegExp _westMarkHan = RegExp('([$_west%‰])(\\*{1,3}|`)([$_han])');
/// 纯文本版:用于标题、副题、简介等 Text 控件。
String cjkAutoSpace(String text) {
var s = text;
s = s.replaceAllMapped(_hanWest, (m) => '${m[1]}$_thin${m[2]}');
s = s.replaceAllMapped(_westHan, (m) => '${m[1]}$_thin${m[2]}');
return s;
}
/// markdown 版:跳过 fenced code block,并处理强调/行内码边界。
String cjkMarkdownAutoSpace(String md) {
final lines = md.split('\n');
var inFence = false;
for (var i = 0; i < lines.length; i++) {
final t = lines[i].trimLeft();
if (t.startsWith('```') || t.startsWith('~~~')) {
inFence = !inFence;
continue;
}
if (inFence) continue;
var s = lines[i];
s = s.replaceAllMapped(_hanMarkWest, (m) => '${m[1]}$_thin${m[2]}${m[3]}');
s = s.replaceAllMapped(_westMarkHan, (m) => '${m[1]}${m[2]}$_thin${m[3]}');
lines[i] = cjkAutoSpace(s);
}
return lines.join('\n');
}