| |
| |
| |
| |
|
|
| import { browserLocale } from './locale'; |
|
|
| export interface SentenceSpan { |
| text: string; |
| start: number; |
| end: number; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| function makeSegmenter(): Intl.Segmenter | null { |
| if (typeof Intl === 'undefined' || !('Segmenter' in Intl)) return null; |
| for (const locale of [browserLocale(), 'en']) { |
| try { |
| return new Intl.Segmenter(locale, { granularity: 'sentence' }); |
| } catch { |
| |
| } |
| } |
| return null; |
| } |
|
|
| const segmenter = makeSegmenter(); |
|
|
| export function splitSentences(text: string): SentenceSpan[] { |
| if (!text) return []; |
| const spans: SentenceSpan[] = []; |
| if (segmenter) { |
| for (const seg of segmenter.segment(text)) { |
| const trimmed = seg.segment.trim(); |
| if (trimmed.length === 0) continue; |
| spans.push({ text: trimmed, start: seg.index, end: seg.index + seg.segment.length }); |
| } |
| return spans; |
| } |
| |
| const re = /[^.!?]+[.!?]+(\s+|$)|[^.!?]+$/g; |
| let m: RegExpExecArray | null; |
| while ((m = re.exec(text)) !== null) { |
| const trimmed = m[0].trim(); |
| if (trimmed.length > 0) spans.push({ text: trimmed, start: m.index, end: m.index + m[0].length }); |
| } |
| return spans; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| export function endsSentence(text: string): boolean { |
| return /[.!?]["')\]]?\s*$/.test(text) || /\n\s*$/.test(text); |
| } |
|
|