mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-10-27 23:35:17 -07:00
fix(anki): regenerate sentence furigana from the final sentence (#268)
This commit is contained in:
1 parent
b0fb39a8f5
commit
7c161723cd
16 files changed
+489
-18
No files matched your search
@@ -0,0 +1,87 @@
|
||||
type Segment = { text: string; reading?: string };
|
||||
|
||||
function readGroups(value: unknown): Segment[][] | null {
|
||||
if (!Array.isArray(value)) return null;
|
||||
const groups: Segment[][] = [];
|
||||
const rawGroups: unknown[] = value;
|
||||
for (const group of rawGroups) {
|
||||
if (!Array.isArray(group)) return null;
|
||||
const segments: Segment[] = [];
|
||||
const rawSegments: unknown[] = group;
|
||||
for (const segment of rawSegments) {
|
||||
if (
|
||||
typeof segment !== 'object' ||
|
||||
segment === null ||
|
||||
!('text' in segment) ||
|
||||
typeof segment.text !== 'string' ||
|
||||
('reading' in segment &&
|
||||
segment.reading !== undefined &&
|
||||
typeof segment.reading !== 'string')
|
||||
)
|
||||
return null;
|
||||
segments.push({
|
||||
text: segment.text,
|
||||
reading:
|
||||
'reading' in segment && typeof segment.reading === 'string' ? segment.reading : undefined,
|
||||
});
|
||||
}
|
||||
groups.push(segments);
|
||||
}
|
||||
return groups;
|
||||
}
|
||||
|
||||
function escapeText(text: string): string {
|
||||
return text
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/\[/g, '[')
|
||||
.replace(/\]/g, ']');
|
||||
}
|
||||
|
||||
// Only accept a complete parse, so a lookup of just the headword cannot replace sentence context.
|
||||
export function formatSentenceFurigana(
|
||||
text: string,
|
||||
results: unknown[] | null,
|
||||
highlightedText?: string,
|
||||
): string | null {
|
||||
for (const result of results ?? []) {
|
||||
if (typeof result !== 'object' || result === null || !('content' in result)) continue;
|
||||
const groups = readGroups(result.content);
|
||||
if (
|
||||
!groups ||
|
||||
groups
|
||||
.flat()
|
||||
.map((segment) => segment.text)
|
||||
.join('') !== text
|
||||
)
|
||||
continue;
|
||||
const highlights: number[] = [];
|
||||
if (highlightedText) {
|
||||
let start = text.indexOf(highlightedText);
|
||||
while (start >= 0) {
|
||||
highlights.push(start);
|
||||
start = text.indexOf(highlightedText, start + highlightedText.length);
|
||||
}
|
||||
}
|
||||
let offset = 0;
|
||||
let bold = false;
|
||||
let output = '';
|
||||
for (const { text: surface, reading } of groups.flat()) {
|
||||
const start = offset;
|
||||
offset += surface.length;
|
||||
const highlighted = highlights.some(
|
||||
(position) => position < offset && position + (highlightedText?.length ?? 0) > start,
|
||||
);
|
||||
if (highlighted !== bold) output += highlighted ? '<b>' : '</b>';
|
||||
bold = highlighted;
|
||||
const escaped = escapeText(surface);
|
||||
output +=
|
||||
reading && reading !== surface && /[\p{Script=Han}々]/u.test(surface)
|
||||
? ` ${escaped}[${escapeText(reading)}]`
|
||||
: escaped;
|
||||
}
|
||||
return output + (bold ? '</b>' : '');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
Reference in new issue
Block a user