更新换行算法和APP-PUSH

This commit is contained in:
吕新雨
2026-02-10 11:39:33 +08:00
parent f03d36b5e9
commit ee2d9f44ea
105 changed files with 9967 additions and 233 deletions

View File

@@ -0,0 +1,78 @@
import type { Breakpoint } from './types';
import type { Token } from '../core/types';
type TcCandidateConfig = {
tcPunctuations: string[];
balanceRange: number;
};
/**
* 计算 BALANCE 的 idealPos 列表(确定性简化版)。
*
* - N=tokens.length
* - targetLines=min(maxLines,N)
* - lineIndex in 1..targetLines-1
* idealPos=round(N*lineIndex/targetLines)
*/
export function computeTcIdealPositions(tokens: Token[], maxLines: number): number[] {
const n = tokens.length;
const targetLines = Math.max(1, Math.min(maxLines | 0, n));
const ideals: number[] = [];
for (let lineIndex = 1; lineIndex <= targetLines - 1; lineIndex++) {
const idealPos = Math.round((n * lineIndex) / targetLines);
ideals.push(idealPos);
}
// 去重并排序(稳定)
ideals.sort((a, b) => a - b);
return ideals.filter((v, idx) => idx === 0 || v !== ideals[idx - 1]);
}
/**
* TC 候选断点生成:
* - 标点后kind=PUNCTpriority=30
* - 空格后kind=SPACEpriority=20
* - BALANCEkind=BALANCEpriority=5围绕 idealPos ± balanceRange
*
* 注意BALANCE 断点允许生成在短语 span 内,是否可用交给评分阶段强惩罚淘汰。
*/
export function generateTcCandidates(tokens: Token[], maxLines: number, config: TcCandidateConfig): { candidates: Breakpoint[]; idealPositions: number[] } {
const n = tokens.length;
if (n <= 1) return { candidates: [], idealPositions: [] };
const punctSet = new Set(config.tcPunctuations);
const candidates: Breakpoint[] = [];
// PUNCT / SPACE扫描 token
for (let i = 0; i < n; i++) {
const t = tokens[i]?.text ?? '';
const pos = i + 1;
// 只允许行内断点
if (pos < 1 || pos > n - 1) continue;
if (punctSet.has(t)) {
candidates.push({ pos, kind: 'PUNCT', priority: 30 });
}
if (t === ' ') {
candidates.push({ pos, kind: 'SPACE', priority: 20 });
}
}
// BALANCE
const idealPositions = computeTcIdealPositions(tokens, maxLines);
const range = Math.max(0, config.balanceRange | 0);
if (range > 0 && idealPositions.length > 0) {
for (const ideal of idealPositions) {
for (let pos = ideal - range; pos <= ideal + range; pos++) {
if (pos < 1 || pos > n - 1) continue;
candidates.push({ pos, kind: 'BALANCE', priority: 5 });
}
}
}
return { candidates, idealPositions };
}