Word JS分句函数网页版Range.expandTo报错,桌面版正常求助
Word网页版中
Range.expandTo导致realsentenizer函数崩溃的修复方案 问题描述
realsentenizer函数在桌面版Microsoft® Word for Microsoft 365 MSO(版本2309 Build 16.0.16827.20130 64位)运行完全正常,但在网页版Office(已测试最新版Chrome和Edge)里会崩溃。崩溃点在console.log('break15.5')之后、console.log('break16')之前的await context.sync()语句,调试信息显示问题出在Range.expandTo方法上。
这个函数的作用是按.分割文档正文生成句子,同时保护clause 5.6、registration no. 555这类不该分割的含.场景。
问题根源
网页版Word的JavaScript API在处理文档结构变更后的Range对象时,和桌面版存在兼容性差异:
- 函数先通过替换操作保护特殊点,之后又恢复原文本,这个过程改变了文档结构
- 原代码复用了之前获取的
sentences数组中的Range对象,这些对象在文档结构变更后已经失效,网页版API调用expandTo时无法识别失效的Range,从而触发崩溃 - 原代码
else分支里的saved_range = sentences.items[i+1]存在数组越界风险,网页版对这类错误的容错性更低
修复方案
1. 恢复保护文本后重新获取句子Range
不再复用之前的sentences对象,在恢复所有保护文本后,重新调用getTextRanges获取最新的句子Range集合,确保所有Range都是基于当前文档结构的有效引用。
2. 修复循环越界问题
在else分支中添加边界判断,避免i+1超出数组长度导致的错误。
3. 优化Range合并逻辑
减少对旧Range对象的依赖,确保每次合并操作都使用最新的有效Range。
修改后的完整代码
var global_sentences3_text = [] var global_sentences3_ranges = [] var global_sentences_real = null var global_contract_body = null async function realsentenizer() { await Word.run(async (context) => { const body = context.document.body.getRange(); body.load("text"); await context.sync(); console.log('break1') // 保存全文本用于后续API分析 global_contract_body = body.text console.log('break2') /// 保护特殊点开始 /// // 按顺序处理,避免重复匹配同一内容导致重复恢复 var saved_text = [] var ranges_to_protect = body.search("[0-9].[0-9]", {matchWildcards: true, matchCase: false}) console.log('break3') ranges_to_protect.load('text') console.log('break4') await context.sync() console.log('break5') for (let i = 0; i < ranges_to_protect.items.length ; i++) { saved_text.push(ranges_to_protect.items[i].text) ranges_to_protect.items[i].insertText('[PROTECTEDDOT]','Replace') } console.log('break6') await context.sync() var saved_text2 = [] var ranges_to_protect2 = body.search("[Nn][Oo].", {matchWildcards: true, matchCase: false}) ranges_to_protect2.load('text') await context.sync() for (let i = 0; i < ranges_to_protect2.items.length ; i++) { saved_text2.push(ranges_to_protect2.items[i].text) ranges_to_protect2.items[i].insertText('[PROTECTEDDOT]','Replace') } await context.sync() console.log('break7') var saved_text3 = [] var ranges_to_protect3 = body.search("[0-9].", {matchWildcards: true, matchCase: false}) ranges_to_protect3.load('text') await context.sync() for (let i = 0; i < ranges_to_protect3.items.length ; i++) { saved_text3.push(ranges_to_protect3.items[i].text) ranges_to_protect3.items[i].insertText('[PROTECTEDDOT]','Replace') } await context.sync() console.log('break8') var saved_text4 = [] var ranges_to_protect4 = body.search("[Cc][Ff].", {matchWildcards: true, matchCase: false}) ranges_to_protect4.load('text') await context.sync() for (let i = 0; i < ranges_to_protect4.items.length ; i++) { saved_text4.push(ranges_to_protect4.items[i].text) ranges_to_protect4.items[i].insertText('[PROTECTEDDOT]','Replace') } await context.sync() console.log('break9') var saved_text6 = [] var ranges_to_protect6 = body.search("[A-Za-z].[A-Za-z]", {matchWildcards: true, matchCase: false}) ranges_to_protect6.load('text') await context.sync() for (let i = 0; i < ranges_to_protect6.items.length ; i++) { saved_text6.push(ranges_to_protect6.items[i].text) ranges_to_protect6.items[i].insertText('[PROTECTEDDOT]','Replace') } await context.sync() console.log('break10') /// 保护特殊点结束 /// // 替换含whereas和;的句子中的;为.,避免生成过长的引言句 const pseudo_sentences = body.getTextRanges([" ."], false) pseudo_sentences.load('text') await context.sync() console.log('break11') var ranges_to_protect5 = [] var searched_ranges = null for (let i = 0; i < pseudo_sentences.items.length ; i++) { if (pseudo_sentences.items[i].text.toLowerCase().includes('whereas') && pseudo_sentences.items[i].text.includes(';')){ searched_ranges = pseudo_sentences.items[i].search(";", {matchWildcards: true, matchCase: false}) searched_ranges.load('text') await context.sync() for (let j = 0; j < searched_ranges.items.length ; j++) { ranges_to_protect5.push(searched_ranges.items[j]) searched_ranges.items[j].insertText('.','Replace') } } } await context.sync(); console.log('break12') // 分割文本获取句子Range const sentences = body.getTextRanges([" ."], false); sentences.load('text') global_sentences_real = sentences await context.sync() console.log('break13') // 恢复保护的文本 for (let i = 0; i < ranges_to_protect.items.length ; i++) { ranges_to_protect.items[i].insertText(saved_text[i],'Replace') } for (let i = 0; i < ranges_to_protect2.items.length ; i++) { ranges_to_protect2.items[i].insertText(saved_text2[i],'Replace') } for (let i = 0; i < ranges_to_protect3.items.length ; i++) { ranges_to_protect3.items[i].insertText(saved_text3[i],'Replace') } for (let i = 0; i < ranges_to_protect4.items.length ; i++) { ranges_to_protect4.items[i].insertText(saved_text4[i],'Replace') } for (let i = 0; i < ranges_to_protect5.length ; i++) { ranges_to_protect5[i].insertText(";",'Replace') } for (let i = 0; i < ranges_to_protect6.items.length ; i++) { ranges_to_protect6.items[i].insertText(saved_text6[i],'Replace') } await context.sync() console.log('break14') // 关键修复:恢复文本后重新获取最新的句子Range,避免使用失效的旧Range const fresh_sentences = body.getTextRanges([" ."], false); fresh_sentences.load('text'); await context.sync(); const new_ranges =[] let saved_range = fresh_sentences.items[0] let extended_range = {}; console.log('break15') console.log(fresh_sentences.items.length) // 遍历合并相邻Range for (let i = 1; i < fresh_sentences.items.length ; i++) { console.log(`ITERATION: ${i}`) console.log('for_start') if (!fresh_sentences.items[i].text.includes(" .")){ console.log('if_1') extended_range = saved_range.expandTo(fresh_sentences.items[i]) console.log('if_2') extended_range.load('text') console.log('if_3') saved_range = extended_range console.log('if_4') } else { extended_range = saved_range.expandTo(fresh_sentences.items[i]) console.log('else_1') extended_range.load('text') console.log('else_2') new_ranges.push(extended_range) console.log('else_3') // 修复越界问题:判断i+1是否在数组范围内 if (i+1 < fresh_sentences.items.length) { saved_range = fresh_sentences.items[i+1] } else { // 处理最后一个元素的情况 break; } console.log('else_4') } console.log('for_end') } console.log('LOOP END FULL') // 确保最后一个Range被加入 if (saved_range) { new_ranges.push(saved_range) } console.log('break15.5') await context.sync(); console.log('break16') /// 处理全大写标题逻辑 /// var new_ranges2 = [] for (let i = 0; i < new_ranges.length ; i++) { new_ranges[i].load('text') await context.sync(); // 先加载文本再判断 if (new_ranges[i].text.toUpperCase() === new_ranges[i].text){ if (i+1 < new_ranges.length) { // 避免越界 const new_range = new_ranges[i].expandTo(new_ranges[i+1]) new_range.load('text') new_ranges2.push(new_range) i += 1 } else { new_ranges2.push(new_ranges[i]) } } else { new_ranges2.push(new_ranges[i]) } } await context.sync() console.log('break17') /// 处理全大写标题逻辑结束 /// for (let sentence of new_ranges2) { sentence.load('text') await context.sync(); global_sentences3_text.push(sentence.text) sentence.track() global_sentences3_ranges.push(sentence) } await context.sync() for (let sentence of global_sentences3_text) { console.log(sentence) } console.log('break18') global_sentences_real.track() await context.sync() console.log('成功完成分句') }); }
内容的提问来源于stack exchange,提问作者HighPriestPete
相关产品推荐
相关产品推荐

